<?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[CodeArtify Blog]]></title><description><![CDATA[Learn how to apply Software Craftsmanship, Domain-Driven Design, Refactoring, Code Quality, TDD, agile software development and more in your team or company!]]></description><link>https://codeartify.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!w-jy!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5ad9b2d-df18-4ca4-b854-56a55c510ddc_853x853.png</url><title>CodeArtify Blog</title><link>https://codeartify.substack.com</link></image><generator>Substack</generator><lastBuildDate>Sun, 17 May 2026 02:21:32 GMT</lastBuildDate><atom:link href="https://codeartify.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Oliver Zihler]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[info@codeartify.com]]></webMaster><itunes:owner><itunes:email><![CDATA[info@codeartify.com]]></itunes:email><itunes:name><![CDATA[Oliver Zihler]]></itunes:name></itunes:owner><itunes:author><![CDATA[Oliver Zihler]]></itunes:author><googleplay:owner><![CDATA[info@codeartify.com]]></googleplay:owner><googleplay:email><![CDATA[info@codeartify.com]]></googleplay:email><googleplay:author><![CDATA[Oliver Zihler]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Ports & Adapters-Style Architectures: Ditching the Dogma for Pragmatism]]></title><description><![CDATA[Avoid unmaintainable software due to Ports & Adapters-style architectures by separating the advantageous from the optional on a per-use-case basis.]]></description><link>https://codeartify.substack.com/p/ditching-the-dogma-for-pragmatism</link><guid isPermaLink="false">https://codeartify.substack.com/p/ditching-the-dogma-for-pragmatism</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 13 Jun 2025 06:01:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!fdYH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Ports &amp; Adapters Under Fire</h2><p>Recently, I got the impression that Ports &amp; Adapters (PA)-style codebase structures have come under a lot of pressure. Reasons may be the various definitions found on the internet that make it hard to know which one to follow; the many port abstraction interfaces and associated mappings between core and outside world; or the class explosion per folder if the entire system only contains one core, data access, and presentation folder without further structuring into bounded contexts, &#8220;features&#8221;, or use cases. </p><p>Whatever the exact reason, in this article, I discuss what I think are elements of PA-style architectures that can be left out and on the other hand what elements are really advantageous to avoid unnecessary coupling to code and data that is not under our control. </p><p>It&#8217;s probably not conclusive so if you want to discuss further topics, just ask it in the chat :) Let&#8217;s get started!</p><p>If you want to get started on Hexagonal Architecture, check out my first blog post here: </p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;a3df1479-ca85-420e-8481-dcabd5bf8997&quot;,&quot;caption&quot;:&quot;Hexagonal Architecture?&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;From Layered to Hexagonal Architecture in 2 steps&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:101472580,&quot;name&quot;:&quot;Oliver Zihler&quot;,&quot;bio&quot;:&quot;I work constantly towards a software engineering world where work is enjoyable and sustainable, code is easy to read and extend, and agile practices produce the highest customer value possible.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55609b24-f24e-41c5-afa5-a7393b5d9c99_281x281.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-02-07T07:20:10.414Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:141453331,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:18,&quot;comment_count&quot;:6,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;CodeArtify Blog&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5ad9b2d-df18-4ca4-b854-56a55c510ddc_853x853.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2>Lose the Ports</h2><p>A key problem with PA-style architectures is that they inherently come with what may feel like unnecessary abstractions - the ports themselves!</p><p>A port is a method signature that exposes either primitive data types or data structures from within. Such an approach essentially leads the &#8220;outside&#8221; of the hexagon to depend on the core of it, not the other way round.</p><p>Are these port interfaces actually needed? Not necessarily. The main idea is that the methods of the core hexagon don&#8217;t expose any outside data structures. If we simply follow this guideline and adhere to the dependency inversion principle, we don&#8217;t need port interfaces and instead can use the actual implementation directly.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fdYH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fdYH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 424w, https://substackcdn.com/image/fetch/$s_!fdYH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 848w, https://substackcdn.com/image/fetch/$s_!fdYH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 1272w, https://substackcdn.com/image/fetch/$s_!fdYH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fdYH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png" width="1126" height="887" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:887,&quot;width&quot;:1126,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:107731,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7aab0265-adc6-4812-bf17-344c2dc0aef1_1126x887.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_!fdYH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 424w, https://substackcdn.com/image/fetch/$s_!fdYH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 848w, https://substackcdn.com/image/fetch/$s_!fdYH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.png 1272w, https://substackcdn.com/image/fetch/$s_!fdYH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b60ed5-6eee-4e81-be89-acdf536958df_1126x887.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><figcaption class="image-caption">Ports can add an unnecessary indirection that, especially in the case of 1 implementation per port, can increase complexity and make navigation harder than needed.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!U9b5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!U9b5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 424w, https://substackcdn.com/image/fetch/$s_!U9b5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 848w, https://substackcdn.com/image/fetch/$s_!U9b5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 1272w, https://substackcdn.com/image/fetch/$s_!U9b5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!U9b5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png" width="1739" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1739,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113631,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd351a454-9c90-404c-9470-c7038a5ebe73_1739x574.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_!U9b5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 424w, https://substackcdn.com/image/fetch/$s_!U9b5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 848w, https://substackcdn.com/image/fetch/$s_!U9b5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.png 1272w, https://substackcdn.com/image/fetch/$s_!U9b5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63389e9-b1c5-4444-9bb9-e373effaaf6d_1739x574.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><figcaption class="image-caption">Simply inlining the port while adhering to the dependency inversion principle (only return core-specific data structures from external systems and databases) can remove such unnecessary indirections without losing the benefits.</figcaption></figure></div><p>The mapping does not disappear like that, unfortunately, but at least when traversing the application, we don&#8217;t have to awkwardly jump in and out of interface definition files.</p><h2>What About Inbound Ports?</h2><p>In my opinion, the last port I usually introduce is that of the inbound port. In most cases, there is only one implementation of that port and should it be replaced by a test double, it can easily be achieved by existing frameworks or vanilla inheritance. </p><p>Outbound ports may be reasonable especially when we want to replace an existing with a new one without the Hexagon knowing about it - but because an interface can be extracted in a blink of an eye, we may also <em>wait this out until the actual need arises.</em> </p><p>Simply adhering to the dependency inversion principle also in the implementation of the outbound adapter class avoids the need to add interfaces yet.</p><h2>Service? Use Case!</h2><p>I often see generic service classes implementing all the inbound port interfaces. That way, all the use cases are summarised in a single service for convenience. However, this makes it hard to split out cohesive, vertical use-case slices which simplifies their discovery.</p><p>If there is one contribution of Clean Architecture that solves this problem, in my opinion, it is the Use Case granularity of the hexagon core. One use case may contain a couple of (private) methods, but only the actual use case method is invoked by a controller. This increases cohesiveness and reduces coupling from unrelated use-case methods. </p><p>Should we provide only one controller for all the publicly exposed API methods, at least we can structure the application core simply by different use case classes. We don&#8217;t even need additional folders anymore within that application folder to separate the use cases. Use cases become first class citizens in this screaming, domain-centric architecture.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7bBf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7bBf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 424w, https://substackcdn.com/image/fetch/$s_!7bBf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 848w, https://substackcdn.com/image/fetch/$s_!7bBf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 1272w, https://substackcdn.com/image/fetch/$s_!7bBf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7bBf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png" width="1234" height="809" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1234,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124031,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.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_!7bBf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 424w, https://substackcdn.com/image/fetch/$s_!7bBf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 848w, https://substackcdn.com/image/fetch/$s_!7bBf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.png 1272w, https://substackcdn.com/image/fetch/$s_!7bBf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ce9b76-b009-4d61-9071-38431476d8af_1234x809.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>If we additionally apply the idea from before and leave the inbound ports out, the controller&#8217;s member variables basically stay as expressive as before, but navigating the code is simplified.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NBIi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NBIi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 424w, https://substackcdn.com/image/fetch/$s_!NBIi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 848w, https://substackcdn.com/image/fetch/$s_!NBIi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 1272w, https://substackcdn.com/image/fetch/$s_!NBIi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NBIi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png" width="1456" height="676" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:676,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:109847,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.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_!NBIi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 424w, https://substackcdn.com/image/fetch/$s_!NBIi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 848w, https://substackcdn.com/image/fetch/$s_!NBIi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.png 1272w, https://substackcdn.com/image/fetch/$s_!NBIi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F502dbeb9-d095-4d12-88be-f636d97ab200_1466x681.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><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Want to learn more about effective software design? In our blog, we discuss emerging trends and proven concepts for you to know exactly how to prompt your AI and avoid a procedural code mess. Stay up-to-date by subscribing!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Vertical Use Case Slice?</h2><p>A next natural step from the above idea is to create a controller per use case. This also makes sense from a cohesion point of view. That means the following:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jzIX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jzIX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 424w, https://substackcdn.com/image/fetch/$s_!jzIX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 848w, https://substackcdn.com/image/fetch/$s_!jzIX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 1272w, https://substackcdn.com/image/fetch/$s_!jzIX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jzIX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png" width="1280" height="780" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:780,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102473,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.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_!jzIX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 424w, https://substackcdn.com/image/fetch/$s_!jzIX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 848w, https://substackcdn.com/image/fetch/$s_!jzIX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.png 1272w, https://substackcdn.com/image/fetch/$s_!jzIX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55d11728-fb77-423a-9748-d4cb94d13832_1280x780.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>But now we have to ask ourselves what we gain from the additional abstractions if we always have a controller- and use-case pair. We are basically back to Onion Architecture&#8217;s &#8220;CustomerController&#8221;, &#8220;CustomerService&#8221;, now on a use case granularity. So naturally, we could just inline the entirety of the use case into the controller:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1o3c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1o3c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 424w, https://substackcdn.com/image/fetch/$s_!1o3c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 848w, https://substackcdn.com/image/fetch/$s_!1o3c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 1272w, https://substackcdn.com/image/fetch/$s_!1o3c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1o3c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png" width="1403" height="712" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e688789a-c287-4581-950d-71b6cf0beb68_1403x712.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:712,&quot;width&quot;:1403,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77573,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.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_!1o3c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 424w, https://substackcdn.com/image/fetch/$s_!1o3c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 848w, https://substackcdn.com/image/fetch/$s_!1o3c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.png 1272w, https://substackcdn.com/image/fetch/$s_!1o3c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe688789a-c287-4581-950d-71b6cf0beb68_1403x712.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>And inject the adapters for databases and external systems directly. And maybe even rename the controller to use case?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8oX1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8oX1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 424w, https://substackcdn.com/image/fetch/$s_!8oX1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 848w, https://substackcdn.com/image/fetch/$s_!8oX1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 1272w, https://substackcdn.com/image/fetch/$s_!8oX1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8oX1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png" width="1428" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1428,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:94128,&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://codeartify.substack.com/i/165454470?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.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_!8oX1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 424w, https://substackcdn.com/image/fetch/$s_!8oX1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 848w, https://substackcdn.com/image/fetch/$s_!8oX1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.png 1272w, https://substackcdn.com/image/fetch/$s_!8oX1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1218b2a1-b105-4334-bf57-ea8430955a1e_1428x700.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>We may have to adjust transaction boundaries and move them from the use case method to the controller method instead. But else, there is actually nothing wrong with such a setup. We basically have arrived at a vertical-slice architecture. </p><p>Any repository or surrounding system can directly be called from the controller/use case. Because data-access classes may be used with various use cases in the same bounded context, we can add them to an external data access folder within a bounded context (or move it even outside into a shared module if other bounded contexts need to access it, too).</p><p>So the structure may look like:</p><pre><code>app 
|_ shared_data_access
|_ bounded_context_1
|_ bounded_context_2
  |_ use_cases
    |_ CreateXUseCase
    |_ CreateYUseCase
  |_ data_access
    |_ ExternalSystemAdapter
    |_ ExternalSystem</code></pre><p>Which flattens the traditional modules to use cases and data access. </p><h2>Dependency Inversion? Anti-Corruption!</h2><p>I&#8217;d keep dependency inversion on the outbound side even if no outbound ports are employed. A simple adapter class can map between use case and external system. I feel this mapping is important to avoid coupling with an external system or database that may not be under our direct control. The adapter effectively becomes an <em>Anti-Corruption Layer</em>.</p><p>If the data access is under our control, we may even leave out this external system adapter and directly access the database or repository connector. In any case, I recommend to separate data-access logic from business logic even if the code remains rather procedural. </p><p>If that proofs too difficult to achieve within one team, separating the two concerns using abstractions like classes and functions with own data structures can simplify maintainability. </p><h2>No Architecture At All?</h2><p>Let&#8217;s face it: most of the code we create is not rocket science. We basically move data from A to B, with a bit of logic for manipulation in between. The important separation is that of the 3 concerns <em>presentation, business logic, data access</em>. </p><p>The data we present to the user may not be the same as the one we need for business calculations, and the data access may store different fields again for optimisation reasons. This is often true for command-like operations, meaning use cases that change a state. So having 3 different data representations may actually proof reasonable, except when we simply map the same fields between different concerns.</p><p>On the other hand, query-like operations (getters) can provide precomputed views that don&#8217;t require any mapping at all. Having additional data structures for core and adapters, where we map the same data items multiple times without any logic in between, is a maintainability nightmare. Here, PA-style architectures are simply in the way of maintainable software.</p><p>If team members have mastered this logical separation between data access, presentation, and business logic (which doesn&#8217;t take longer than a couple of weeks of active practicing), they should be able to decide on a use-case basis how much abstraction is actually needed.</p><h2>A Final Word</h2><p>Software Architecture, even if only used within a Modulith to structure low-level code, is still architecture. This means we need to make architectural decisions: we need to weigh pros and cons of every decision against each other with incomplete understanding and information. </p><p>This also means that we sometimes get it wrong. There is simply no silver-bullet solution template that we can apply to every software design problem, even though I feel that many software engineers want exactly that.</p><p>Instead, we need to be aware of all the possibilities we have to structure our code, be it all inlined procedural code per use case or full-blown Clean Architecture (which, in my opinion, generally will be too over-engineered), how to identify and resolve problematic software design, and how to quickly move from one design to another, either through manual refactoring or well-formed prompts if we want to give AI a shot.</p><p>This is hard. And the more we practice, the better we become. Instead of pretending we know everything, we should work together and leave our ego at the door. Every idea and decision has pros and cons, and some may be better suited than others. But most ideas are not absolutely wrong. </p><p>If the software works according to specification or user feedback and is simple to change with no to few bugs, the design is the right one, regardless of how much Ports &amp; Adapters was applied or not. </p><p>We need to judge design according to our ability to create, change and maintain it cheaply, not on &#8220;how it looks like&#8221;. Only then will we create software that actually solves the problem of their users. And only then will they come back to us and ask for more. </p><h3><strong>Want to learn more?</strong></h3><p>Curious to go deeper?</p><p>Our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>  covers in detail how to get from a Layered- to Hexagonal-, Clean-, and even Vertical-Slice Architecture and the pro&#8217;s and con&#8217;s of each approach. </p><p>This overview will equip you with the theoretical and practical knowledge needed to guide your AI assistant into the right direction during development and avoids creating a procedural mess in the process!</p><p>We also provide remote, hybrid, and on-site workshops on Software Design and Architectural Design Patterns like Hexagonal- and Vertical-Slice Architecture which you can find on our <a href="https://codeartify.com/en/courses">website - codeartify.com</a>.</p><p>Check it out!</p>]]></content:encoded></item><item><title><![CDATA[EventStorming: A Smooth Start into the Workshop]]></title><description><![CDATA[Real-world tips for facilitating domain modeling and system design that get devs and business working together productively]]></description><link>https://codeartify.substack.com/p/eventstorming-a-smooth-start</link><guid isPermaLink="false">https://codeartify.substack.com/p/eventstorming-a-smooth-start</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 06 Jun 2025 07:02:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gwtl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>EventStorming and Event Modeling are great techniques to collaboratively explore domains and design (event-driven) systems. However, getting started can feel awkward at first. That&#8217;s why I want to share my experience - what helped me get over the initial hesitation so that everyone can benefit from the workshop.</p><h3>Why So Many Sticky Colours?</h3><p>The full set of stickies used in both EventStorming and Event Modeling can feel overwhelming in the beginning. But especially if the goal is to start exploring a problem domain with everyone involved (like developers, business reps, stakeholders), all we actually need are <em>Domain Events</em>.</p><p>The best discussions often emerge when we start jotting down what we believe is happening in the domain using Domain Events, placing them on a <em>Timeline</em> that shows which event comes after which. That&#8217;s it.</p><p>These discussions naturally surface misunderstandings and help align everyone&#8217;s mental model. This alone can massively improve collaboration and reduce friction once development starts.</p><p>We should only introduce more stickies if there's a clear need. The logical next stickies are Actors and External Systems, since someone or something needs to trigger those Domain Events.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gwtl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gwtl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 424w, https://substackcdn.com/image/fetch/$s_!gwtl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 848w, https://substackcdn.com/image/fetch/$s_!gwtl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 1272w, https://substackcdn.com/image/fetch/$s_!gwtl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gwtl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png" width="781" height="717" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:717,&quot;width&quot;:781,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97947,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://codeartify.substack.com/i/164538160?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0339a284-7ba5-40ce-9a87-c08197a11a5a_939x1064.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_!gwtl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 424w, https://substackcdn.com/image/fetch/$s_!gwtl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 848w, https://substackcdn.com/image/fetch/$s_!gwtl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 1272w, https://substackcdn.com/image/fetch/$s_!gwtl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9adc01f8-845c-4bb7-8517-f3884a2014ba_781x717.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">The only thing needed for a great first workshop are Domain Events and the Timeline (the sequence in which these events happen). Actors and External Systems may be added, too, but may be optional in the first couple of hours of event gathering.</figcaption></figure></div><h3>What is a Domain Event?</h3><p>A common source of hesitation is the term "Domain Event" itself. Workshops often start with something like, &#8220;Let&#8217;s collect all the events that can happen in our domain.&#8221; But this can immediately raise questions like: &#8220;What do you mean by an event?&#8221;, &#8220;Why are we talking about things in the past?&#8221;, or just a general &#8220;This feels weird.&#8221;</p><p>It&#8217;s not always easy to explain what a Domain Event is. But here&#8217;s something that&#8217;s worked well for me in many cases: a Domain Event represents something meaningful that has already happened in the business domain. It&#8217;s something that the system (or others) might want to react to.</p><p>For example: A user submits an address form. After the address is successfully stored, we publish an event like &#8220;AddressSubmitted&#8221; to inform other parts of the system what happened. That&#8217;s a Domain Event.</p><p>Of course, not every Domain Event needs to involve a state change, but thinking of them as the result of some meaningful outcome helps people get started.</p><h3>Use Domain Language, not CRUD</h3><p>We&#8217;re all conditioned to think in CRUD terms: Create, Read, Update, Delete. But when we model using Domain Events, that mindset gets in the way.</p><p>Even business stakeholders might talk in CRUD terms because they've absorbed our technical language. That&#8217;s why we need to be intentional about using the domain&#8217;s own language during these workshops.</p><p>Take &#8220;AddressSubmitted&#8221; for example. A CRUD mindset might have started with Domain Events named &#8220;AddressCreated&#8221; or &#8220;AddressUpdated.&#8221; But such names lose important context. If someone updates their address because they moved, <em>why</em> they moved might affect what the system needs to do next.</p><p>A concrete example might be a Swiss tax system. Here, different rules apply depending on whether someone moved within the same municipality, to another one, or abroad. So instead of just &#8220;AddressUpdated,&#8221; we might model each Domain Event separately as:</p><ul><li><p>MovedWithinMunicipality</p></li><li><p>MovedToAnotherMunicipality</p></li><li><p>MovedAbroad</p></li></ul><p>This makes the system clearer, more explicit, and easier to evolve.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">We want to make software development a collaborative activity where everyone can bring their strengths to the table and nobody feels left out! We believe only this way we can create the most effective systems, especially in the age of AI! Subscribe to support us in our endeavour!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Domain Events for Different Granularities</h3><p>Sure, we <em>could</em> just emit a general &#8220;AddressUpdated&#8221; event and let downstream systems figure out whether it was relevant for them or not. But that leads to unnecessary complexity and wasted computation. Having more explicit Domain Events generally keeps things cleaner and more maintainable. </p><p>The granularity of Domain Events isn&#8217;t a hard science. It depends on your domain, your team, and how the system is supposed to behave. The key is to let the discussions guide the granularity, and be okay with evolving it over time as your understanding deepens.</p><h3>Event Modeling / Storming is Agile</h3><p>In general, these workshops are not meant for Big Design Up Front. They work best when used with an agile mindset: increment &#8594; feedback &#8594; iterate.</p><p>We want to collaboratively build a shared mental model of the business domain. There are no absolute &#8220;rights&#8221; or &#8220;wrongs.&#8221; Each round of discussion improves the model.</p><p>The more questions we raise during an initial session, the better. They signal gaps in understanding, which are perfect opportunities for exploration and experimentation.</p><p>These models are lightweight and often inaccurate in the beginning. But that&#8217;s fine. Real clarity tends to emerge once implementation starts, iteratively.</p><p>Some teams have tried using these techniques to plan 3 years of development in advance and were disappointed with the result. That&#8217;s not surprising as it contradicts the agile spirit these workshops are built on.</p><h3>LLMs in Collaborative Workshops</h3><p>One final note: I do believe that AI tools like LLMs can actually support a more iterative and collaborative approach.</p><p>They let us cheaply experiment with ideas, generate working examples, and validate flows without needing to build full mockups that rarely reflect real product behaviour anyway.</p><p>Even better, consulting LLMs regularly helps speed up decision-making. We no longer have to awkwardly piece together everyone&#8217;s fragmented knowledge but can use AI as a thinking partner to get clearer, faster.</p><p>This is one of the most exhausting parts of traditional workshops: everyone trying to explain their fragmented understanding, often in inconsistent ways. LLMs might help bridge those gaps if used thoughtfully.</p><p>I&#8217;m genuinely hopeful that AI will improve how we collaborate and ultimately lead to better software that solves real problems, faster and cheaper.</p><p>Let&#8217;s see where it takes us :)</p><h3>Want to learn more?</h3><p>Curious to go deeper?</p><p>Our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a> extensively covers both Big Picture EventStorming and Design-Level EventStorming for you to get started with the topic in more depth.</p><p>We also provide remote, hybrid, and on-site workshops on EventStorming, either exclusively as a <a href="https://codeartify.com/en/courses/deep-dive-event-storming">deep-dive</a> or integrated into the wider context of <a href="https://codeartify.com/en/courses/event-storming-ddd-and-clean-architecture">collaborative software development</a>. </p><p>Check it out! :)</p>]]></content:encoded></item><item><title><![CDATA[Legacy Code Modernisation: Speeding Up Approval Test Writing with CombinationsApproval]]></title><description><![CDATA[Manually writing Approval Tests can become cumbersome, especially if various input parameter combinations exist. Libraries like ApprovalTests can mitigate these problems.]]></description><link>https://codeartify.substack.com/p/combinations-approval</link><guid isPermaLink="false">https://codeartify.substack.com/p/combinations-approval</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 04 Apr 2025 06:00:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8beaf840-c235-4211-840e-2058a957e983_1878x1424.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In a <a href="https://codeartify.substack.com/p/approval-testing">previous article</a>, I showed how to write approval tests manually. This method can easily be employed in small codebases, but larger functions with many input parameters can make it cumbersome to write tests for every parameter combination.</p><p><a href="https://approvaltests.com/">Approval Tests</a> is a library that makes it very easy to automate that task. It provides <em>CombinationApprovals</em>: for every defined input parameter, the library automatically creates every combination of them, easily covering a multitude of test cases with a single test. </p><p>I will show here how to install and apply it to your codebase, and some pitfalls to avoid when setting it up.</p><h2>Approval Testing</h2><p>The basic idea of combinations approval testing is the same as described in my article on <a href="https://codeartify.substack.com/p/approval-testing">manual approval testing</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UYO8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UYO8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 424w, https://substackcdn.com/image/fetch/$s_!UYO8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 848w, https://substackcdn.com/image/fetch/$s_!UYO8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!UYO8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UYO8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png" width="1600" height="1214" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1214,&quot;width&quot;:1600,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:295278,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UYO8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 424w, https://substackcdn.com/image/fetch/$s_!UYO8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 848w, https://substackcdn.com/image/fetch/$s_!UYO8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!UYO8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9122a9c2-44dc-4349-947f-65258542a711_1600x1214.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">The 5 steps to Approval Testing.</figcaption></figure></div><p>There are 5 steps to manually writing Approval Tests (<strong>DAAARt &#127919;</strong>):</p><ol><li><p><em><strong>D</strong>efine</em>: what method should be tested</p></li><li><p><em><strong>A</strong>ct</em>: call the method under test</p></li><li><p><em><strong>A</strong>rrange</em>: add missing dependencies</p></li><li><p><em><strong>A</strong>ssert</em>: the state of affected object as string</p></li><li><p><em><strong>R</strong>un <strong>t</strong>est coverage</em>: to see what branches have not been covered yet</p></li></ol><h2>Installing the Library</h2><p><a href="https://approvaltests.com/builds/">Builds</a> can be found for a variety of languages. I&#8217;m using the <a href="https://mvnrepository.com/artifact/com.approvaltests/approvaltests">Java Maven dependency</a> for these examples:</p><pre><code>&lt;dependency&gt;
    &lt;groupId&gt;com.approvaltests&lt;/groupId&gt;
    &lt;artifactId&gt;approvaltests&lt;/artifactId&gt;
    &lt;version&gt;24.17.0&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre><h2>Understanding the Library Function</h2><p>I use the following <a href="https://github.com/codeartify/examples/tree/main/src/main/java/com/codeartify/examples/parking_spot_reservation/controller">codebase</a>. Like in the previous article, I will create an approval test for the outermost controller method:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-ESS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-ESS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 424w, https://substackcdn.com/image/fetch/$s_!-ESS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 848w, https://substackcdn.com/image/fetch/$s_!-ESS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 1272w, https://substackcdn.com/image/fetch/$s_!-ESS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-ESS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png" width="1456" height="395" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:395,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:109653,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.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_!-ESS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 424w, https://substackcdn.com/image/fetch/$s_!-ESS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 848w, https://substackcdn.com/image/fetch/$s_!-ESS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.png 1272w, https://substackcdn.com/image/fetch/$s_!-ESS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29992029-66f1-4fba-a47c-593fe3db4238_1650x448.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>ParkingSpotReservationController::reserveParkingSpot takes a ParkingSpotReservationService as a constructor input and ParkingReservationRequest as a method parameter. </p><p>Let&#8217;s create a usual Unit Test for it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qrxv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qrxv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 424w, https://substackcdn.com/image/fetch/$s_!Qrxv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 848w, https://substackcdn.com/image/fetch/$s_!Qrxv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 1272w, https://substackcdn.com/image/fetch/$s_!Qrxv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qrxv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png" width="1396" height="848" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:848,&quot;width&quot;:1396,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:172911,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.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_!Qrxv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 424w, https://substackcdn.com/image/fetch/$s_!Qrxv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 848w, https://substackcdn.com/image/fetch/$s_!Qrxv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.png 1272w, https://substackcdn.com/image/fetch/$s_!Qrxv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76af85d9-e848-4b06-b58c-424c38653c6c_1396x848.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>The method I&#8217;m interested in is <em>CombinationApprovals.verifyAllCombinations()</em>. This method takes 2 types of inputs: </p><ol><li><p>The method to test as a <code>Function</code></p></li><li><p>0 - N input parameters into that method, each represented as <code>InputType[]{}</code></p></li></ol><p>The arrays for the input parameters allow the framework to automatically <strong>generate all combinations</strong>, increasing coverage. We don&#8217;t need to manually consider every possible input combination anymore.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Too much legacy code needs revival! Join our quest for better software solutions by subscribing to our blog! :)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Creating a Testing Function</h2><p>Let&#8217;s create the Function to pass to verifyAllCombinations. The behaviour we want to fix in place is the following:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9OTF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9OTF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 424w, https://substackcdn.com/image/fetch/$s_!9OTF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 848w, https://substackcdn.com/image/fetch/$s_!9OTF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 1272w, https://substackcdn.com/image/fetch/$s_!9OTF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9OTF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png" width="1456" height="67" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:67,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23015,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.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_!9OTF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 424w, https://substackcdn.com/image/fetch/$s_!9OTF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 848w, https://substackcdn.com/image/fetch/$s_!9OTF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 1272w, https://substackcdn.com/image/fetch/$s_!9OTF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a6538e8-65be-4c24-893c-e2d885335b44_1770x82.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>ParkingSpotReservationController takes 1 service argument in it&#8217;s constructor and 1 request argument in the reserveParkingSpot method. A first approach could be to create a function that passes these two parameters and returns the response, like:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pX-0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pX-0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 424w, https://substackcdn.com/image/fetch/$s_!pX-0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 848w, https://substackcdn.com/image/fetch/$s_!pX-0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 1272w, https://substackcdn.com/image/fetch/$s_!pX-0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pX-0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png" width="1406" height="236" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/af1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:236,&quot;width&quot;:1406,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51861,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.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_!pX-0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 424w, https://substackcdn.com/image/fetch/$s_!pX-0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 848w, https://substackcdn.com/image/fetch/$s_!pX-0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 1272w, https://substackcdn.com/image/fetch/$s_!pX-0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1beb93-246f-4fd7-864f-9d3005bd0d4e_1406x236.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">First approach to create a (static) function to pass to verifyAllCombinations.</figcaption></figure></div><p>However, we don&#8217;t want to stub the ParkingSpotReservationService, which is the argument passed to ParkingSpotReservationController. Like with <a href="https://codeartify.substack.com/p/approval-testing">manual approval tests</a>, only <strong>awkward</strong>, meaning hard-to-instantiate, slow, or nondeterministic dependencies should be stubbed. So we instantiate the service inside that function as-is and pass it to the controller.</p><p>The two dependencies passed to the ParkingSpotReservationService are indeed such awkward dependencies. They are framework-specific JPA repository interfaces (ParkingReservationRepository and ParkingSpotRepository) and should be stubbed and passed to the method:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SaZS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SaZS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 424w, https://substackcdn.com/image/fetch/$s_!SaZS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 848w, https://substackcdn.com/image/fetch/$s_!SaZS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 1272w, https://substackcdn.com/image/fetch/$s_!SaZS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SaZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png" width="1456" height="276" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:276,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79251,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.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_!SaZS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 424w, https://substackcdn.com/image/fetch/$s_!SaZS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 848w, https://substackcdn.com/image/fetch/$s_!SaZS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 1272w, https://substackcdn.com/image/fetch/$s_!SaZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5717da8-f689-465a-ac4a-3e2e03238e0a_1712x324.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">A second approach to the function passes only awkward dependencies while instantiating the service class that is part of our codebase.</figcaption></figure></div><p>Now one issue remains: the returned ResponseEntity&lt;Object&gt; class only has a framework-specific toString() method that we cannot predict what it will return.</p><p>To counter that, as with manual approval tests, we create a static stateAsString method that retrieves only those fields we are interested in. This method will be the state that we want to save to fix the behaviour in place:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!epaE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!epaE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 424w, https://substackcdn.com/image/fetch/$s_!epaE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 848w, https://substackcdn.com/image/fetch/$s_!epaE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 1272w, https://substackcdn.com/image/fetch/$s_!epaE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!epaE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png" width="1456" height="234" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:234,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:65966,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.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_!epaE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 424w, https://substackcdn.com/image/fetch/$s_!epaE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 848w, https://substackcdn.com/image/fetch/$s_!epaE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 1272w, https://substackcdn.com/image/fetch/$s_!epaE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6ca394d-b0f9-4b68-898b-e9643d954d20_1484x238.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The final function to pass to verifyAllCombinations is therefore going to be:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MOQo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MOQo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 424w, https://substackcdn.com/image/fetch/$s_!MOQo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 848w, https://substackcdn.com/image/fetch/$s_!MOQo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 1272w, https://substackcdn.com/image/fetch/$s_!MOQo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MOQo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png" width="1456" height="326" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:326,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:101195,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.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_!MOQo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 424w, https://substackcdn.com/image/fetch/$s_!MOQo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 848w, https://substackcdn.com/image/fetch/$s_!MOQo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 1272w, https://substackcdn.com/image/fetch/$s_!MOQo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc803e602-ddd3-4a84-8790-82d7290ec65d_1708x382.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>It can now be used as a static function call like:</p><pre><code><code>ParkingSpotReservationControllerApprovalTest::createAssertableOutput</code></code></pre><h2>Creating a Test</h2><p>The simplest test that runs through with an empty output looks like the following:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jGpb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jGpb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 424w, https://substackcdn.com/image/fetch/$s_!jGpb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 848w, https://substackcdn.com/image/fetch/$s_!jGpb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 1272w, https://substackcdn.com/image/fetch/$s_!jGpb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jGpb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png" width="1316" height="392" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:392,&quot;width&quot;:1316,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:73870,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.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_!jGpb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 424w, https://substackcdn.com/image/fetch/$s_!jGpb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 848w, https://substackcdn.com/image/fetch/$s_!jGpb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.png 1272w, https://substackcdn.com/image/fetch/$s_!jGpb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F539f124d-29b1-4551-a94b-0f105b2b84e0_1316x392.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>As a result, we get two output files:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bCFH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bCFH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 424w, https://substackcdn.com/image/fetch/$s_!bCFH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 848w, https://substackcdn.com/image/fetch/$s_!bCFH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 1272w, https://substackcdn.com/image/fetch/$s_!bCFH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bCFH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png" width="1416" height="204" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:204,&quot;width&quot;:1416,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66010,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.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_!bCFH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 424w, https://substackcdn.com/image/fetch/$s_!bCFH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 848w, https://substackcdn.com/image/fetch/$s_!bCFH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 1272w, https://substackcdn.com/image/fetch/$s_!bCFH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb8161e1-02f6-45e4-b414-ac4071afc323_1416x204.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>These two output files are currently empty. Once we add working parameters in their respective arrays, these files will contain either the output to assert (received.txt) or the approved output (approved.txt). </p><p>If we run the test again without changing anything, the <em>received.txt</em> file will disappear because we &#8220;approved&#8221; that empty output is the state to fix in place, and the test becomes green.</p><h2>First Output to Assert</h2><p>Now we need to apply DAAARt (see above), So let&#8217;s check the code and arrange the dependencies to test to cover as much of the code as possible per test.</p><p>The first test case that gets into the body of the service and covers as much code as possible can be achieved by creating two stubs for the awkward repository dependencies, one that returns no active reservation, and one that finds an empty spot. Plus, the requested reservation period needs to be within operating hours and at least 30 minutes long. This results in the following code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4oNC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4oNC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 424w, https://substackcdn.com/image/fetch/$s_!4oNC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 848w, https://substackcdn.com/image/fetch/$s_!4oNC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 1272w, https://substackcdn.com/image/fetch/$s_!4oNC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4oNC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png" width="1456" height="1506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1506,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:445974,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.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_!4oNC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 424w, https://substackcdn.com/image/fetch/$s_!4oNC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 848w, https://substackcdn.com/image/fetch/$s_!4oNC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.png 1272w, https://substackcdn.com/image/fetch/$s_!4oNC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08513d25-d3ff-4c7d-9b41-31b4ad95497f_1794x1856.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><figcaption class="image-caption">First test that creates state output to fix the behaviour of the happy path in place.</figcaption></figure></div><p>I intentionally override the toString methods of the two repository stubs and return exactly what their purpose is, withoutActiveReservation and findSpot because it makes it easy to see in the output what test case was covered:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!05AF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!05AF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 424w, https://substackcdn.com/image/fetch/$s_!05AF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 848w, https://substackcdn.com/image/fetch/$s_!05AF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 1272w, https://substackcdn.com/image/fetch/$s_!05AF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!05AF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png" width="1456" height="91" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:91,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:118534,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.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_!05AF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 424w, https://substackcdn.com/image/fetch/$s_!05AF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 848w, https://substackcdn.com/image/fetch/$s_!05AF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 1272w, https://substackcdn.com/image/fetch/$s_!05AF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8cc539b-f24e-42f9-b5d0-bc20ec4462a5_3598x224.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>If we use IntelliJ, we can now simply press the &#187; button in the middle of the screen and add the new parts to the <em>approved.txt</em> file. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V1s4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V1s4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 424w, https://substackcdn.com/image/fetch/$s_!V1s4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 848w, https://substackcdn.com/image/fetch/$s_!V1s4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 1272w, https://substackcdn.com/image/fetch/$s_!V1s4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V1s4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png" width="1456" height="120" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:136098,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.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_!V1s4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 424w, https://substackcdn.com/image/fetch/$s_!V1s4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 848w, https://substackcdn.com/image/fetch/$s_!V1s4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 1272w, https://substackcdn.com/image/fetch/$s_!V1s4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d98cbe-72de-4dd0-861a-afbdabd04d09_3600x296.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now, the contents are identical, and if we run the test again, it becomes green and the <em>received.txt</em> file disappears. </p><p>Let&#8217;s also investigate the test coverage now (see the <a href="https://codeartify.substack.com/approval-testing">other article</a> to learn about viewing test coverage):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kdrn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kdrn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 424w, https://substackcdn.com/image/fetch/$s_!kdrn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 848w, https://substackcdn.com/image/fetch/$s_!kdrn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 1272w, https://substackcdn.com/image/fetch/$s_!kdrn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kdrn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png" width="1456" height="690" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:690,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:253005,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.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_!kdrn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 424w, https://substackcdn.com/image/fetch/$s_!kdrn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 848w, https://substackcdn.com/image/fetch/$s_!kdrn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.png 1272w, https://substackcdn.com/image/fetch/$s_!kdrn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0011ee6-1795-44f4-acc4-7886a74f01e2_1664x788.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>With this 1 test alone, we covered already 74% of all lines of code. By exploring the code first and choosing the input parameters reasonably, we can quickly cover a large portion of the code. </p><h2>Automatically Testing Parameter Combinations</h2><p>If we now add 2 additional parameters, for example two repository stubs for &#8220;withActiveReservation&#8221; and &#8220;findNoSpot&#8221;, we get the following output:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kTZy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kTZy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 424w, https://substackcdn.com/image/fetch/$s_!kTZy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 848w, https://substackcdn.com/image/fetch/$s_!kTZy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 1272w, https://substackcdn.com/image/fetch/$s_!kTZy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kTZy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png" width="1456" height="135" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:135,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:185550,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.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_!kTZy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 424w, https://substackcdn.com/image/fetch/$s_!kTZy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 848w, https://substackcdn.com/image/fetch/$s_!kTZy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 1272w, https://substackcdn.com/image/fetch/$s_!kTZy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9256b559-5847-4edb-8af7-52618c5b3136_3598x334.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now we got 4 (1*2*2) input combinations because the library recombines them all. </p><p>How convenient. In manual approval tests, we would have had to write a test for each combination or use a parameterised test, but even then we would not have received an output that is that easy to update like with received.txt and approved.txt. </p><h2>Quickly Covering Lots of Ground</h2><p>Let&#8217;s try to cover all the branches. With 4 requests, 2 reservation-, and 2 spot repo stubs, we can create 4*2*2 = 16 combinations in 10 lines of code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uxVV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uxVV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 424w, https://substackcdn.com/image/fetch/$s_!uxVV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 848w, https://substackcdn.com/image/fetch/$s_!uxVV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 1272w, https://substackcdn.com/image/fetch/$s_!uxVV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uxVV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png" width="1456" height="401" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:401,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:194480,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.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_!uxVV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 424w, https://substackcdn.com/image/fetch/$s_!uxVV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 848w, https://substackcdn.com/image/fetch/$s_!uxVV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.png 1272w, https://substackcdn.com/image/fetch/$s_!uxVV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3582a66b-1507-40de-ac2b-c41dad1bcc03_2094x576.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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XDWC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XDWC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 424w, https://substackcdn.com/image/fetch/$s_!XDWC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 848w, https://substackcdn.com/image/fetch/$s_!XDWC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 1272w, https://substackcdn.com/image/fetch/$s_!XDWC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XDWC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png" width="1456" height="406" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:406,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:460298,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.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_!XDWC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 424w, https://substackcdn.com/image/fetch/$s_!XDWC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 848w, https://substackcdn.com/image/fetch/$s_!XDWC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.png 1272w, https://substackcdn.com/image/fetch/$s_!XDWC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc64e34-63c7-49dc-a4b0-817b3cafd0de_3174x884.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>By using this framework, we can be sure not to miss combinations like we could with manual approval tests. Even though at the moment some cases may not be relevant, as soon as we start refactoring, we could create code that could </p><h2>Handling Issues with Line Breaks</h2><p>Depending on the IDE used, it may happen that even though the result of the approval tests didn&#8217;t change, the IDE appends a whitespace after each line. In IntelliJ, this can be avoided by using the following line in the .editorconfig:</p><pre><code><code>trim_trailing_whitespace = false</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DOSP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DOSP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 424w, https://substackcdn.com/image/fetch/$s_!DOSP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 848w, https://substackcdn.com/image/fetch/$s_!DOSP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 1272w, https://substackcdn.com/image/fetch/$s_!DOSP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DOSP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png" width="1456" height="806" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:806,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:461014,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!DOSP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 424w, https://substackcdn.com/image/fetch/$s_!DOSP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 848w, https://substackcdn.com/image/fetch/$s_!DOSP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.png 1272w, https://substackcdn.com/image/fetch/$s_!DOSP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92918edb-47d6-40b6-8b83-cecdb209ac40_2366x1310.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><figcaption class="image-caption">Without trim_trailing_whitespace = false in the .editorconfig, test outputs of CombinationsApproval are never equal.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!svjF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!svjF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 424w, https://substackcdn.com/image/fetch/$s_!svjF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 848w, https://substackcdn.com/image/fetch/$s_!svjF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 1272w, https://substackcdn.com/image/fetch/$s_!svjF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!svjF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png" width="1218" height="66" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:66,&quot;width&quot;:1218,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26981,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!svjF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 424w, https://substackcdn.com/image/fetch/$s_!svjF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 848w, https://substackcdn.com/image/fetch/$s_!svjF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 1272w, https://substackcdn.com/image/fetch/$s_!svjF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F476b0d22-4733-432f-b729-a3504a2bfd05_1218x66.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Tests run through again after adding trim_trailing_whitespace = false. </figcaption></figure></div><h1>Example</h1><p>See the full example in the following video:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;decee32c-4cd3-463e-8d36-60b7b1028385&quot;,&quot;duration&quot;:null}"></div><h1>Conclusion </h1><p>I have demonstrated how CombinationApproval can fix a method&#8217;s behaviour quickly in place, much faster than doing it manually using manual approval tests, while simultaneously combining all the parameters to create more test cases. </p><p>With these tests in place, we can be more confident when we make changes to the code that it will not break.</p><p>Another important technique that can help us finding uncovered combinations is called Mutation Testing. In a next article, I will explore what it is and how to apply it, and how it can be used in Legacy applications to improve confidence in test coverage even more.</p><h1>Resources</h1><p>To get rid of the yellow test name, you can change the test name pattern in IntelliJ to </p><pre><code><code>[A-Z][A-Za-z\d]*(Test(s|Case)?|Should|TestShould)|Test[A-Z][A-Za-z\d]*|IT(.*)|(.*)IT(Case)?</code> </code></pre><p>in the following menu:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eHaa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eHaa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 424w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 848w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 1272w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eHaa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png" width="1456" height="853" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/afd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:853,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:720349,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.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_!eHaa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 424w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 848w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 1272w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.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>To effectively refactor Legacy code, we need to have a specific goal towards we want to move our design. Our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a> can help with that, as it introduces Domain-Driven Design and how to implement Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn how to effectively separate concerns in Legacy code and move your application towards a better design, you could also have a look at our on-premise, remote or hybrid workshops <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a> and <a href="https://codeartify.com/en/courses/untangle-legacy-code-with-domain-driven-refactoring">Untangle Your Legacy Code with Domain-Driven Refactoring</a>, where we dive into the presented topics in much greater detail.</p><p>To effectively learn how to identify code smells and refactor them, check out our workshop on <a href="https://codeartify.com/en/courses/clean-code-workshop">Clean Code</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Haven&#8217;t subscribed yet? Join me on my quest for better software solutions! :)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Legacy Code Modernisation - Conserving Behaviour with Approval Tests]]></title><description><![CDATA[Transitioning legacy code to Hexagonal Architecture requires a strong test suite. Approval Tests are a powerful tool to achieve this.]]></description><link>https://codeartify.substack.com/p/approval-testing</link><guid isPermaLink="false">https://codeartify.substack.com/p/approval-testing</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 28 Mar 2025 07:01:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6b48e62d-a166-49ae-bda3-b9932a31182f_1878x1424.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Why Legacy Code Needs Tests</h1><p>Refactoring means <em>changing the internal structure of the code without changing its observable behaviour to make it easier to understand and cheaper to modify</em> (<a href="https://martinfowler.com/bliki/DefinitionOfRefactoring.html">Martin Fowler</a>). </p><p>We thus need to refactor code continuously to remain able to save or make money for our business. If maintaining or changing our code makes us lose money, refactoring it can have many advantages over rebuilding it from scratch as the business knowledge is already there, it just needs to be brought back to light. </p><p>However, to be able to refactor code effectively without potentially introducing bugs while doing so, we need a strong set of effective and preferably fast, tests. </p><p>Legacy code typically lacks sufficient test coverage to refactor effectively. If it had, it would not be considered legacy code, as it would allow for frequent, cheap changes. </p><p>Thus, we need a way to test legacy code without falling into analysis paralysis or potentially introducing bugs while improving its design.</p><p>A proven solution to this problem are so-called <strong>Pin-Down-, Characterisation-, </strong>or <strong>Approval Tests</strong>: quickly written, fast throwaway unit tests that pin the current behaviour in place while avoiding the mental overload and structural problems of writing &#8220;real&#8221; unit tests for legacy code. </p><p>This test harness then becomes the insurance for refactoring the code and improving its design incrementally, avoiding costly rewrites in the process.</p><p>In this article, I want to focus on writing Approval Tests manually to understand the concept and have a technique at hand that requires no additional dependencies, which can be useful for small legacy methods.</p><p>In future articles, I will introduce some useful libraries that build on this knowledge but automate a lot of the manual steps, helping pinning down behaviour of larger legacy methods with lots of input parameter combinations.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">We want to spread the word about effective software development - and each new subscriber lets us know our content matters! :) Subscribe to join us on this journey! :)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h1>Testing Legacy Code with Approval Tests</h1><p>You can try it out yourself in the following <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parking_spot_reservation/controller/ParkingSpotReservationController.java">codebase</a>.</p><p>There are 5 steps to manually writing Approval Tests (remember <strong>DAAARt &#127919;</strong>):</p><ol><li><p><em><strong>D</strong>efine</em>: what method should be tested</p></li><li><p><em><strong>A</strong>ct</em>: call the method under test</p></li><li><p><em><strong>A</strong>rrange</em>: add missing dependencies</p></li><li><p><em><strong>A</strong>ssert</em>: the state of affected object as string</p></li><li><p><em><strong>R</strong>un <strong>t</strong>est coverage</em>: to see what branches have not been covered yet</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Rm4x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Rm4x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 424w, https://substackcdn.com/image/fetch/$s_!Rm4x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 848w, https://substackcdn.com/image/fetch/$s_!Rm4x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!Rm4x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Rm4x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png" width="1456" height="1105" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1105,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Rm4x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 424w, https://substackcdn.com/image/fetch/$s_!Rm4x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 848w, https://substackcdn.com/image/fetch/$s_!Rm4x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!Rm4x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff810b526-0b46-46ef-91f1-a62693ae6546_1600x1214.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><figcaption class="image-caption">The five steps (DAAARt) to writing Approval Tests</figcaption></figure></div><h3>Defining Appropriate Methods to Test</h3><p>We want to start as far out as possible, for example with a REST controller or a use case service method, so that we cover <em>as much code as possible</em> with one test and don&#8217;t end up tying our code to our test. This means many classes may possibly be tested together.</p><p>I typically create a unit test that ends in &#8220;ApprovalTestShould&#8221; to indicate its purpose, for example ParkingSpotReservationApprovalTestShould.</p><h3>Acting and Arranging</h3><p>We start by creating a unit test that simply instantiates the class containing the  method, and pass all parameters to the constructor or method as <em>null</em>. </p><p>Then we run the test. This inevitably will lead to null pointer exceptions (NPEs) and other errors, which we need to fix, typically by injecting the required dependencies step-by-step.</p><p>We choose to inject as much production code from our own codebase as possible, and only resort to injecting <a href="https://martinfowler.com/bliki/TestDouble.html">test doubles</a> (&#8220;mocks&#8221;) for <em>awkward dependencies</em>. </p><p>Awkward dependencies are those that are slow or non-deterministic. Typical examples include: </p><ul><li><p>I/O</p></li><li><p>Database</p></li><li><p>Filesystem</p></li><li><p>Random Number Generator</p></li><li><p>Time</p></li></ul><p>We continue acting and arranging, which I like to refer to as &#8220;<em>sledgehammering our way through the code</em>&#8221;, until we reach the bottom of the code and the test runs through without errors and becomes <em>green</em>. Naturally, it&#8217;s only green because we <em>do not assert anything yet</em>. This changes in the next step.</p><h3>Asserting with stateAsString()</h3><p>We assert the state of the object under test, or whatever object the method returns, as a simple string. </p><p>We can either use the <em>toString</em> method if it contains the entirety of the state, or write a dedicated <em>stateAsString</em> method on that object to indicate that this method is only intended for Approval Testing. </p><p>In general, I&#8217;d recommend using the dedicated stateAsString method not to interfere with changes that may get introduced along the way to official toString methods.</p><p>A stateAsString method could look as follows:</p><pre><code><code>String stateAsString() {
    return "name: " + this.name + ", age: " + this.age + ";
}</code></code></pre><p>If we cannot define a stateAsString() method on the result value because it is a framework-specific class, we can still create it inside the test class as a static method:</p><pre><code>private String stateAsString(ResponseEntity&lt;Object&gt; result) {
    return "body: " + result.getBody() + 
           ", "status code: " + result.getStatusCode();
}</code></pre><p>Initially, we don&#8217;t know yet what the stateAsString() method will return. This is why we start by simply asserting an empty string against the state as a string:</p><pre><code>assertEquals(&#8220;&#8221;, unitUnderTest.stateAsString());</code></pre><p>This will inevitably lead to the test finally failing for the right reason. We want that to happen: we can now simply <em>take the output of the test comparison as is and place it in the empty string of the assertion method</em>. </p><pre><code><code>assertEquals(&#8220;name: Olly, age: old&#8221;, unitUnderTest.stateAsString());</code></code></pre><p>Now we run the test again and it will pass.</p><h3>Running Test Coverage</h3><p>The final step before the cycle repeats is to <em>run test coverage</em> and see how much code was covered by that test. We always try to cover as much code in one go as possible. Test coverage can be found in IntelliJ e.g. if we click on the 3 dots next to the &#8220;run&#8221; button:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aiOG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aiOG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 424w, https://substackcdn.com/image/fetch/$s_!aiOG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 848w, https://substackcdn.com/image/fetch/$s_!aiOG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 1272w, https://substackcdn.com/image/fetch/$s_!aiOG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aiOG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png" width="1210" height="414" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:414,&quot;width&quot;:1210,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102642,&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://codeartify.substack.com/i/153301623?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6297f7d8-ec17-4e9e-ab90-4ddd92524518_1210x414.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_!aiOG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 424w, https://substackcdn.com/image/fetch/$s_!aiOG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 848w, https://substackcdn.com/image/fetch/$s_!aiOG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.png 1272w, https://substackcdn.com/image/fetch/$s_!aiOG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d50857b-35d0-44f5-b7f4-00bce6e52297_1210x414.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><figcaption class="image-caption">Clicking the 3 dots next to the &#8220;run&#8221; button allows coverage to be shown.</figcaption></figure></div><p>You also need to make sure that all the packages for which coverage should be shown are included in the test configuration:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z6jy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z6jy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 424w, https://substackcdn.com/image/fetch/$s_!z6jy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 848w, https://substackcdn.com/image/fetch/$s_!z6jy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 1272w, https://substackcdn.com/image/fetch/$s_!z6jy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z6jy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png" width="2354" height="1508" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1508,&quot;width&quot;:2354,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:473429,&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://codeartify.substack.com/i/153301623?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcd7e8d-f2b5-4f15-a306-e24cb817b1d7_2354x1508.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_!z6jy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 424w, https://substackcdn.com/image/fetch/$s_!z6jy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 848w, https://substackcdn.com/image/fetch/$s_!z6jy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.png 1272w, https://substackcdn.com/image/fetch/$s_!z6jy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F972a5010-b4f0-457c-89d9-f642c35df4c8_2354x1508.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><figcaption class="image-caption">Make sure you add all the packages containing classes that are referenced by the class under test to get coverage information when running the test with coverage.</figcaption></figure></div><p>Once we run these tests with coverage, we can find on the left side 3 colours indicating coverage:</p><ul><li><p><em>green</em>: covered by tests</p></li><li><p><em>red</em>: not covered by tests</p></li><li><p><em>yellow</em>: covered at least once, but not with every possible combination.</p></li></ul><p>Our goal is to get to cover as much as possible, or have a good understanding why some parts of the code are still yellow or even red (e.g. due to unreachable code).</p><p>We get additional information about class, method, line, and branch coverage in the window that opens when we run coverage, as can be seen in the following screenshot:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0NOM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0NOM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 424w, https://substackcdn.com/image/fetch/$s_!0NOM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 848w, https://substackcdn.com/image/fetch/$s_!0NOM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 1272w, https://substackcdn.com/image/fetch/$s_!0NOM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0NOM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png" width="1456" height="318" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:318,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:387587,&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://codeartify.substack.com/i/153301623?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.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_!0NOM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 424w, https://substackcdn.com/image/fetch/$s_!0NOM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 848w, https://substackcdn.com/image/fetch/$s_!0NOM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 1272w, https://substackcdn.com/image/fetch/$s_!0NOM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1ea4a2-8b6d-4d00-b267-a9f13c503d15_3436x750.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Green, yellow, and red coverage on the left of the code, and detailed coverage information on the right side when using IntelliJ.</figcaption></figure></div><p>Any branch not covered by a test becomes the target for the next test. We simply adapt a couple of parameters to reach those branches without losing too much brain capacity to think the algorithm through, and repeat the DAAARt coverage cycle until we are confident enough that our tests cover enough to be able to start refactoring.</p><h1>Example</h1><p>In the video below I show how to write a first manual Approval Testsuite, step-by-step. You can find the solution on the branch manual-approval-testing in the <a href="https://github.com/codeartify/examples/blob/manual-approval-testing/src/test/java/com/codeartify/examples/parking_spot_reservation/controller/ParkingSpotReservationControllerApprovalTestShould.java">codebase</a>.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;c9974a16-77d0-4880-b81f-9a4d6cd95bda&quot;,&quot;duration&quot;:null}"></div><h1>Combinatorial Explosion</h1><p>It is a good idea to practice such a manual technique in order to have it ready should you encounter an untested legacy method and need to refactor and extend it without breaking it in the process.</p><p>However, a method with lot&#8217;s of input parameter combinations can make it very cumbersome to cover all the branches with tests. That is why tools like <a href="https://github.com/approvals/ApprovalTests.java">ApprovalTests</a> exist. In a future article, I will show how to employ this tool too. </p><p>It builds on the same ideas introduced here, so it&#8217;s a good idea to practice the concepts first before moving to such a tool.</p><h1>Conclusion</h1><p>Testing legacy code is not trivial. By employing Approval Testing, we can circumvent the issues of analysing code by simply asserting whatever the code returns, and then mutating input values until we covered all branch combinations.</p><p>These tests form the basis for further refactoring endeavours by providing an effective safety net that can be kept for the entire time of the legacy code rejuvenation.</p><p>Just remember the 5 steps involved: <strong>DAAARt &#127919;</strong></p><ol><li><p><strong>D</strong>efine which method to test</p></li><li><p><strong>A</strong>ct</p></li><li><p><strong>A</strong>rrange</p></li><li><p><strong>A</strong>ssert</p></li><li><p><strong>R</strong>un <strong>t</strong>est coverage</p></li></ol><p>In a next article, I will show how to employ libraries to streamline the process of writing Approval Tests.</p><h1>Resources</h1><p>To get rid of the yellow test name, you can change the test name pattern in IntelliJ to </p><pre><code><code>[A-Z][A-Za-z\d]*(Test(s|Case)?|Should|TestShould)|Test[A-Z][A-Za-z\d]*|IT(.*)|(.*)IT(Case)? </code></code></pre><p>in the following menu:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eHaa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eHaa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 424w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 848w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 1272w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eHaa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png" width="1456" height="853" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/afd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:853,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:720349,&quot;alt&quot;:&quot;&quot;,&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://codeartify.substack.com/i/154815802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!eHaa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 424w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 848w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.png 1272w, https://substackcdn.com/image/fetch/$s_!eHaa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd74733-8bda-4aaa-a69a-173c8fb0a4b6_2598x1522.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>To effectively refactor Legacy code, we need to have a specific goal towards we want to move our design. Our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a> can help with that, as it introduces Domain-Driven Design and how to implement Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn how to effectively separate concerns in Legacy code and move your application towards a better design, you could also have a look at our on-premise, remote or hybrid workshops <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a> and <a href="https://codeartify.com/en/courses/untangle-legacy-code-with-domain-driven-refactoring">Untangle Your Legacy Code with Domain-Driven Refactoring</a>, where we dive into the presented topics in much greater detail.</p><p>To effectively learn how to identify code smells and refactor them, check out our workshop on <a href="https://codeartify.com/en/courses/clean-code-workshop">Clean Code</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Every subscriber matters! We can only improve software quality worldwide by joining forces! :) Subscribe now:</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[From Hexagonal- to Clean Architecture]]></title><description><![CDATA[Introduction to Clean Architecture, comparison with Hexagonal Architecture, and incorporation of Domain-Driven-Design Domain Models.]]></description><link>https://codeartify.substack.com/p/from-hexagonal-to-clean-architecture</link><guid isPermaLink="false">https://codeartify.substack.com/p/from-hexagonal-to-clean-architecture</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 21 Mar 2025 07:02:16 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/025c6d06-591a-4539-8061-f2b41e1f055d_2285x1458.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In some of my latest articles, I moved from a typical Spring Boot application through concern separation and dependency inversion towards a Hexagonal Architecture. </p><p>Uncle Bob&#8217;s Clean Architecture adds additional rules and nomenclature to the Hexagon. In this article, I want to explore the commonalities and differences and how we can easily move to from Hexagonal to Clean Architecture.</p><h1>Hexagonal Architecture</h1><p>Let&#8217;s recap the basic Hexagonal Architecture components:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cOrp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cOrp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 424w, https://substackcdn.com/image/fetch/$s_!cOrp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 848w, https://substackcdn.com/image/fetch/$s_!cOrp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 1272w, https://substackcdn.com/image/fetch/$s_!cOrp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cOrp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png" width="2279" height="1435" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1435,&quot;width&quot;:2279,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:479872,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!cOrp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 424w, https://substackcdn.com/image/fetch/$s_!cOrp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 848w, https://substackcdn.com/image/fetch/$s_!cOrp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 1272w, https://substackcdn.com/image/fetch/$s_!cOrp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cba3a7-1425-4cda-967a-c439bd21c873_2279x1435.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">Hexagonal Architecture building blocks.</figcaption></figure></div><p>The hexagon can effectively be divided into outside- and inside components. </p><p>The inside of the hexagon contains the actual application. This can be a service method. It communicates with the outside world through ports, which effectively are interfaces that contain either primitive types or types defined within the app. No outside dependencies can be found in the app. It is typically devoid of any framework dependency.</p><p>The outside of the hexagon can be divided in driving and driven sides depending on which side of the diagonal they are. Driving adapters use (inbound) ports to map data from an outside source to the internal format of the app, and call (drive) the app through that port. If we practice TDD, the first driving adapter is going to be a test.</p><p>On the driven side, we can distinguish between repositories, which are data-access and -storage units to which an application can read to and write from using (outbound) ports. These are bidirectional accesses, so the app can also receive updates from these adapters.</p><p>On the other hand, also unidirectional messaging adapters exist that can simply be referred to as recipients. These recipients can be fire-and-forget queues or emails, or also a website that receives the view model.</p><p>Importantly, driving adapters <em>use </em>ports to invoke an action on the app, while driven adapters implement the port interfaces and are called by the app through those interfaces. This effectively is a combination of dependency inversion and interface segregation, placing the business app into the center.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Support our endeavour to improve application design, maintain- and evolvability by subscribing to our blog! :) Let&#8217;s create a brighter software design future, together! :)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h1>From Hexagonal- to Clean Architecture</h1><p><a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html">Clean Architecture</a> builds on Hexagonal Architecture by providing some additional rules and nomenclature to it. The main idea however is exactly the same - separate business concerns from outside presentation- and data-access concerns. It&#8217;s a bit like applying certain DDD concepts onto the Hexagon, even though Uncle Bob never really mentions DDD in that context for whatever reason. Let&#8217;s see how it compares.</p><p>I intentionally kept some of Hexagonal Architecture&#8217;s building blocks even though the typical Clean Architecture diagram uses circles to emphasise that if you know how to hexagon, you easily get how to clean:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I2km!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I2km!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 424w, https://substackcdn.com/image/fetch/$s_!I2km!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 848w, https://substackcdn.com/image/fetch/$s_!I2km!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 1272w, https://substackcdn.com/image/fetch/$s_!I2km!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I2km!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png" width="2260" height="1392" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1392,&quot;width&quot;:2260,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:528204,&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://codeartify.substack.com/i/154880679?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e595c17-0516-4b84-885e-1d3461eea599_2387x1675.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_!I2km!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 424w, https://substackcdn.com/image/fetch/$s_!I2km!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 848w, https://substackcdn.com/image/fetch/$s_!I2km!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.png 1272w, https://substackcdn.com/image/fetch/$s_!I2km!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa30ed2b1-1e53-4425-ae8a-1e4738d426ef_2260x1392.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><figcaption class="image-caption">Clean Architecture building blocks.</figcaption></figure></div><h2><strong>Use Case instead of &#8220;App&#8221; or &#8220;Inside&#8221;</strong></h2><p>While Hexagonal Architecture stays (intentionally?) vague about the size of the inside of the app, Clean Architecture emphasises a &#8220;use case&#8221; split. A typical use case could be <em>ReserveParkingSpotUseCaseInteractor</em> or similar business-domain actions, which typically are single <em>application-service</em> <em>methods</em>. </p><p>Uncle Bob uses &#8220;Interactor&#8221; for the implementation names because the inbound port interfaces are named &#8220;UseCase&#8221;, e.g. <em>ReserveParkingSpotUseCase</em>. </p><p>I personally prefer to name single method interfaces as actions, so my interface name would be <em>ReserveParkingSpot</em>, while the actual implementation would be <em>ReserveParkingSpotUseCase</em>. But that&#8217;s up to the author of course.</p><p>However, the idea of having a set of first-class citizen use cases heavily improves discoverability inside the codebase. </p><p>Imagine talking the same <a href="https://martinfowler.com/bliki/UbiquitousLanguage.html">Ubiquitous Language</a> as business stakeholders and easily searching and finding these use cases quickly inside the codebase without having to skim through large generic services with many methods.</p><p>Use Cases also add a great domain-driven granularity to the hexagon, making them perfectly suited to be grouped into DDD <a href="https://martinfowler.com/bliki/BoundedContext.html">bounded contexts</a> as these quotes from <a href="https://learning.oreilly.com/library/view/learning-domain-driven-design/9781098100124">Learning Domain-Driven Design by Vlad Khononov</a> imply: </p><div class="pullquote"><p>A subdomain resembles a set of interrelated use cases. The use cases are defined by the business domain and the system&#8217;s requirements.</p><p>Use the rule of thumb [&#8230;] to find subdomains: identify sets of coherent use cases that operate on the same data and avoid decomposing them into multiple bounded contexts.</p></div><p>Creating Modular Monoliths / Moduliths may be simplified by identifying use case interactors that belong together and grouping them into a single module, effectively creating a starting point for a domain-driven bounded context. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XcYg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XcYg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 424w, https://substackcdn.com/image/fetch/$s_!XcYg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 848w, https://substackcdn.com/image/fetch/$s_!XcYg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 1272w, https://substackcdn.com/image/fetch/$s_!XcYg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XcYg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png" width="3074" height="1301" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1301,&quot;width&quot;:3074,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:695245,&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://codeartify.substack.com/i/154880679?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F845d23d5-1ec8-49b9-b309-55a47186d44c_3074x1301.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_!XcYg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 424w, https://substackcdn.com/image/fetch/$s_!XcYg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 848w, https://substackcdn.com/image/fetch/$s_!XcYg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.png 1272w, https://substackcdn.com/image/fetch/$s_!XcYg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d39ff1d-1fd0-4f7d-8179-52179007c324_3074x1301.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><figcaption class="image-caption">Clean Architecture&#8217;s use cases can help thinking about cohesive business functionality to group in DDD bounded contexts for better Modulith modularisation.</figcaption></figure></div><p>It all seems to come together with the introduction of use case interactors!</p><p>Use Cases have the same tasks as DDD&#8217;s application services as they are application business rules. In general, they check global validation, load, update, and store <em>entities</em>, and present the result to the outside world through so-called presenters. </p><h2>Entities</h2><p>While Hexagonal Architecture does not specify the internal structure, Clean Architecture adds Entities. Entities represent the critical business rules of an application and could be used in a wide variety of use cases across the company. </p><p>From that description, they basically fulfil a similar role as value objects and entities of the DDD domain model, but Uncle Bob is less precise about it. </p><p>We can see that while Hexagonal Architecture has <em>no</em> definition of how the inside of the hexagon should look like, Clean Architecture at least knows <em>entities</em>. But if you want to be precise with the implementation, then the clearest distinction is to use a DDD domain model as the most internal part of the application, which is also how it is described in <a href="https://learning.oreilly.com/library/view/implementing-domain-driven-design/9780133039900/">Vaughn Vernon&#8217;s </a><em><a href="https://learning.oreilly.com/library/view/implementing-domain-driven-design/9780133039900/">implementing DDD</a></em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kSKt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kSKt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 424w, https://substackcdn.com/image/fetch/$s_!kSKt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 848w, https://substackcdn.com/image/fetch/$s_!kSKt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 1272w, https://substackcdn.com/image/fetch/$s_!kSKt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kSKt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png" width="3790" height="1055" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1055,&quot;width&quot;:3790,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:214537,&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://codeartify.substack.com/i/154880679?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4db1bb1-522c-46a3-b949-8d5b3ca687d0_3790x1055.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_!kSKt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 424w, https://substackcdn.com/image/fetch/$s_!kSKt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 848w, https://substackcdn.com/image/fetch/$s_!kSKt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.png 1272w, https://substackcdn.com/image/fetch/$s_!kSKt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85725fa6-0274-4fde-a291-4e739b92ce62_3790x1055.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><figcaption class="image-caption">Differences in rules defined about the internal structure of the application according to Ports &amp; Adapters, Clean Architecture, and Domain-Driven Design</figcaption></figure></div><p>I personally always use a <em>domain</em> folder instead of an <em>entities</em> folder, even when implementing Clean Architecture, and distinguish between entities and value objects even if I don&#8217;t use a fully blown Domain Model with aggregates.</p><h2><strong>Controllers</strong></h2><p>Taking the name from Model-View-<strong>Controller</strong> MVC, Controllers act as driving adapters that map the input from some view, like a console or web view, to the format the use case requires, and invoke that use case interface. </p><p>Depending on the technology used, Controllers may also be responsible to ensure the output of a use case returned to the view model again. I will show in a follow-up article what I exactly mean by that.</p><h2>Gateways</h2><p>While Hexagonal Architecture distinguishes between Repositories and Recipients, Clean Architecture only knows Gateways. However, these ports and their respective implementations have the exact same purpose and therefore can be uni- or bidirectional, depending on what data they transfer.</p><h2>Presenters</h2><p>Presenters are specialised ports with respective adapters that do not explicitly exist in the world of Hexagonal Architecture, but could be considered specialised Recipients, meaning unidirectional ports/adapters to the view. </p><p>Their purpose is to map between the result of a use case to the respective view model. This means that both success and error cases need to be handled, often leading to at least two ports for presenting them. </p><p>The view model created by presenters should be extremely specific. For example, they should specify the color of a button or font to display, such that the frontend simply fills the values from the backend into the required fields. I have yet to see such an implementation in real life, though.</p><h2>Crossing Boundaries</h2><p>While Hexagonal Architecture does not specify the data that crosses boundaries except that the outside needs to depend on the inside and not the other way round (or be agnostic if primitive types are used), in Clean Architecture, only very simple primitive types, simple data structures like hash maps or DTOs can be used for that purpose. </p><p>That means that gateways do not return entities. Entities are built within the use case. Even though I understand the reason behind it, as I described in <a href="https://codeartify.substack.com/p/domain-model-vs-dtos">this article</a>, I typically follow a more pragmatic approach and return DDD aggregates through these data-access ports to reduce the number of mappings as they can significantly slow down the application.</p><p>Similarly for the inbound ports, I usually use value objects from the domain model to cross boundaries for the same reason. Clean Architecture would do the mapping and validation inside the use case itself. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kq8D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kq8D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 424w, https://substackcdn.com/image/fetch/$s_!kq8D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 848w, https://substackcdn.com/image/fetch/$s_!kq8D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 1272w, https://substackcdn.com/image/fetch/$s_!kq8D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kq8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png" width="3942" height="1014" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1014,&quot;width&quot;:3942,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:594010,&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://codeartify.substack.com/i/154880679?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b7e1f1-6297-4869-8c92-28ada17cc448_3942x1014.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_!kq8D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 424w, https://substackcdn.com/image/fetch/$s_!kq8D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 848w, https://substackcdn.com/image/fetch/$s_!kq8D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.png 1272w, https://substackcdn.com/image/fetch/$s_!kq8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff428ff53-5a7c-4bfb-851b-46c63ecb4baa_3942x1014.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><figcaption class="image-caption">In a pure Clean Architecture, there is a mapping at every border, which could mean mapping in and out at least 9 to 10 times.</figcaption></figure></div><p>Conclusively, if you want to comply 100% with Clean Architecture, you would map a whole lot more between the different concerns than might actually be necessary. It depends on the use case if that is actually really needed, for example if the use case objects should be shared among various teams without exposing their internal structures. </p><h2>Conclusion</h2><p>I have discussed the commonalities and differences of Hexagonal- and Clean Architecture.</p><p>The main contribution is to split the inside into use case parts. This is a great perspective to build any domain-driven application from, as a couple of use cases together can form a bounded context, which helps modularising applications.</p><p>Clean Architecture contains an entity concern at its core, which is a great place to put a DDD domain model into. Such a core is not specified by Hexagonal Architecture.</p><p>More specific rules for ports and adapters like Controller, Gateway, and Presenter add additional clarity, but need to be evaluated on a case-by-case basis which make sense and which do not.</p><p>Data structures used in ports should be simple - only primitive types, Hash Maps or DTOs should be used. No entities should cross the borders, even for database gateway adapters, which means possibly more mapping between the concerns.</p><p>In a next article, I will show how to move from Hexagonal- to Clean Architecture with an example, so subscribe if you don&#8217;t want to miss it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p><strong>We touch on exactly these topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture in one single course</strong>.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>. To effectively learn how to identify code smells and refactor them, a core skill needed to transform your application to Hexagonal- or Clean Architecture, also check out our workshop on <a href="https://codeartify.com/en/courses/clean-code-workshop">Clean Code</a>.</p>]]></content:encoded></item><item><title><![CDATA[Towards Hexagonal Architecture - Folder Structure]]></title><description><![CDATA[I present possible folder structures I used in own projects that capture concern separation, Hexagonal Architecture, and Domain-Driven Design effectively.]]></description><link>https://codeartify.substack.com/p/folder-structures</link><guid isPermaLink="false">https://codeartify.substack.com/p/folder-structures</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 14 Mar 2025 07:02:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ff577c13-c50a-4953-aaec-6da69ba9da22_2716x1794.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When it comes to hexagonal architecture, there are many ways we can structure an application. Some suggestions aim at having one hexagon for the entire app, others separate ports physically from the actual implementation.</p><p>In this article, I want to illustrate what works for me and what I have employed in projects already. This means it&#8217;s an opinionated article, and others may structure it differently. Take it as a source of inspiration, and then adapt it to your personal needs.</p><h2>Basic Folder Structure</h2><p>The basic folder structure of a hexagonal architecture in my projects should always somehow separate the inside from the outside, or the <em>core</em> from the <em>adapters</em>. </p><p>Therefore, a perfectly viable, simple structure could be:</p><pre><code>app_name
|_outside
|_inside</code></pre><p>or</p><pre><code><code>app_name
|_adapter
|_core</code></code></pre><p>Depending on the complexity of the application, <em>app_name</em> can represent </p><ul><li><p>the <a href="https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html">entire application</a> (all the business use cases),</p></li><li><p>a <a href="https://martinfowler.com/bliki/BoundedContext.html">DDD bounded context</a> (sub-domain-related business use cases), </p></li><li><p>a single narrow, <a href="https://www.jimmybogard.com/vertical-slice-architecture/">vertical business-use-case slice</a>, </p></li><li><p>or any other business-driven decision to split up the application, </p></li></ul><p>as long as the slice represents a vertical, business-driven whole, and not some technical, generic, domain-agnostic concept or horizontal split like &#8220;presentation&#8221;, &#8220;data_access&#8221;, &#8220;application&#8221;, &#8220;domain&#8221;. The latter splits will find their places <em>inside</em> each vertical business slice, if useful.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cYOt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cYOt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 424w, https://substackcdn.com/image/fetch/$s_!cYOt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 848w, https://substackcdn.com/image/fetch/$s_!cYOt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 1272w, https://substackcdn.com/image/fetch/$s_!cYOt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cYOt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png" width="1806" height="1573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1573,&quot;width&quot;:1806,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:173096,&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://codeartify.substack.com/i/155148326?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78580b1-5584-4bce-8cd8-8f74be32339f_2066x1936.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_!cYOt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 424w, https://substackcdn.com/image/fetch/$s_!cYOt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 848w, https://substackcdn.com/image/fetch/$s_!cYOt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.png 1272w, https://substackcdn.com/image/fetch/$s_!cYOt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdc236f-b45c-4e8a-8221-47d4545d8020_1806x1573.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><figcaption class="image-caption">The folder structure of a Hexagonal Architecture can encompass different granularities depending on the app&#8217;s complexity. Theoretically, we can have a hexagon for the entire app, a bounded context, a narrow use case, or any other business-driven vertical slice through the system.</figcaption></figure></div><h2>Inbound vs. Outbound</h2><p>If we continue with the &#8220;core&#8221; vs. &#8220;adapter&#8221; names, we can also introduce a <em>port</em> folder inside the core which makes it easy to see how we can interact with the application. </p><p>An additional useful separation inside the adapter and port folder structures can also be to separate them into &#8220;in(bound)&#8221; and &#8220;out(bound&#8221;). That way, we already see that <em>in</em> ports can only be used with <em>in</em> adapters, and <em>out</em> ports with <em>out</em> adapters.</p><pre><code><code>app_name
|_adapter
  |_in
  |_out
|_core
  |_port
    |_in
    |_out</code></code></pre><p>Depending on the kind of adapters employed, it can make sense to add additional information to the adapters that specify what kind of technology they employ. For example, if the inbound adapter is a REST resource, we can add &#8220;web&#8221; to it. Similarly, when we have in-memory and sql data-access repositories, we can add that to the out folder as well:</p><pre><code><code>app_name
|_adapter
  |_in
    |_web
    |_...
  |_out
    |_in_memory
    |_sql
    |_...
|_core
  |_port
    |_in
    |_out</code></code></pre><p><em>Don&#8217;t use technology-specific names for port folders!</em> They are inherently technology-agnostic and therefore should not mirror exactly the adapters&#8217; folder structure besides the in/out parts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If you have made it this far and find my content useful, I would be super happy if you subscribed! :) That way I know that my contributions are valued, which motivates me to create even better content! :)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Domain-Driven Design Folder Names</h2><p>Alternatively, or additionally, we can also employ language from Domain-Driven Design in our folder structure.</p><p>For example, we can add a <em>presentation</em> folder to the <em>in</em>, and <em> data_access</em> to the <em>out</em>. This can become helpful especially when we add other &#8220;out&#8221; adapters, for example for sending messages, emails, or other uni-directional recipients that are not direct data access.</p><p>The core additionally contains the <em>application</em>, and we could move the <em>ports</em> inside of it, indicating them to be part of the application concern. </p><p>Furthermore, if we employ a domain model, we can add an additional folder called <em>domain</em> that can be placed inside the core. I wouldn&#8217;t place it inside <em>application</em> however as it represents a separate concern after all. </p><pre><code><code>app_name
|_adapter
  |_in
    |_presentation
      |_web
      |_...
  |_out
    |_data_access
      |_in_memory
      |_sql
      |_...
|_core
  |_application
    |_port
      |_in
      |_out
  |_domain</code></code></pre><p>In case we need more structure, an additional folder separating values and entities could be added to the domain. Aggregates would become part of that entities folder, or we can add another aggregates folder.</p><pre><code><code>app_name
|_adapter
  |_in
    |_presentation
      |_web
      |_...
  |_out
    |_data_access
      |_in_memory
      |_sql
      |_...
|_core
  |_application
    |_port
      |_in
      |_out
  |_domain
    |_values
    |_entities</code></code></pre><p>The in- and out folders in the adapter folder, and the core folder may become overly nested here and as an alternative, we could simply have the three main folders adapter, application, and domain inside the app_name.</p><pre><code><code>app_name
|_adapter
  |_presentation
    |_web
    |_...
  |_data_access
    |_in_memory
    |_sql 
    |_...
  |_...
|_application
  |_ports
    |_in
    |_out
|_domain
  |_values
  |_entities</code></code></pre><p>As a consequence, my typical high-level folder structure typically looks like:</p><pre><code><code>app_name
|_adapter 
  |_presentation
  |_data_access
|_application  
|_domain </code></code></pre><p>and then I add or split as the application grows. I like this structure because it honours separation of concerns, Hexagonal Architecture, and Domain-Driven Design, while avoiding an overly nested structure. </p><p>Don&#8217;t rack your brain over it. If you don&#8217;t need a folder, simply leave it out. </p><h2>Illustration</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u-Np!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u-Np!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 424w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 848w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1272w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u-Np!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png" width="1456" height="974" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:974,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!u-Np!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 424w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 848w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1272w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.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>The diagram above shows the codebase introduced in the last articles. I left it in an unfinished state regarding its folder structure. This is what I&#8217;m going to change now. I choose the following structure:</p><pre><code><code>parking_spot_reservation
|_adapter 
  |_presentation
    |_dto 
  |_data_access
    |_model
|_application
  |_exception
  |_port
    |_in
    |_out
|_domain
  |_entity
  |_exception 
  |_value</code></code></pre><p>I chose the <em>presentation</em> / <em>data_access</em> / <em>application</em> / <em>domain</em> structure because we immediately find the different concerns and it helps with incorporating domain-driven concepts easily. presentation and data_access are both part of the adapter package. </p><p>I take over the <em>dto</em> and <em>model </em>packages from the original structure and add it to the presentation and data_access packages, respectively, but that&#8217;s completely optional. </p><p>If we work with exceptions, it also makes sense to separate <em>application</em>-specific exceptions, which are thrown only from the service, from those thrown e.g. from a domain value object creation like ReservationDetails. Two additional <em>exception</em> packages in both domain and application folders helps organising them.</p><p>I place Reservation, the only possible DDD aggregate in that example, into the <em>entity</em> package. If the application grew without further splitting, an aggregate package may be added as well to highlight the interaction points for the application service, but that would be overkill just now.</p><p>The colours indicate the different concerns (red = data_access, orange = presentation, lilac = application, light blue = domain).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZIua!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZIua!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 424w, https://substackcdn.com/image/fetch/$s_!ZIua!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 848w, https://substackcdn.com/image/fetch/$s_!ZIua!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 1272w, https://substackcdn.com/image/fetch/$s_!ZIua!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZIua!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png" width="1456" height="1146" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1146,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1453517,&quot;alt&quot;:&quot;&quot;,&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://codeartify.substack.com/i/155148326?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!ZIua!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 424w, https://substackcdn.com/image/fetch/$s_!ZIua!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 848w, https://substackcdn.com/image/fetch/$s_!ZIua!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.png 1272w, https://substackcdn.com/image/fetch/$s_!ZIua!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584097e5-b7f3-49fa-87b6-da75aa947f50_2272x1788.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><figcaption class="image-caption">A possible package structure that honours concern-separation and concepts from both Hexagonal Architecture and Domain-Driven Design.</figcaption></figure></div><p>You can find the example solution on branch package-structure in the <a href="https://github.com/codeartify/examples/tree/package-structure/src/main/java/com/codeartify/examples/parking_spot_reservation">codebase</a>. </p><p>It&#8217;s important to note that the package structure should be as flat as possible as too much nesting can impede navigation and add more complexity than needed. It is always a tradeoff between more structure and a harder to navigate codebase. </p><p>There is no one-size-fits-all solution when it comes to package structure. Every use case needs to be reevaluated. But the high-level structure of adapter-application-domain, with an additional separation of the adapter package to presentation-data_access, provides a great way to start from.</p><h2>Conclusions</h2><p>Different possible package structures exist to organise a Hexagonal Architecture depending on its complexity. A reasonable approach separates inside from outside, or core from adapters.</p><p>If we incorporate the 4 different concerns, we additionally add clarity where to put what. The core can be divided into application and domain, the adapters get two additional packages presentation and data_access.</p><p>The highest level folder can be the entire application or smaller bounded contexts or even use cases. It always depends on the complexity of the application.</p><p>We need to avoid overly complex nested structures as these can hinder quick navigation. It is always a trade-off between more structure and easier access.</p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p><p>To effectively learn how to identify code smells and refactor them, check out our workshop on <a href="https://codeartify.com/en/courses/clean-code-workshop">Clean Code</a>.</p><h2></h2>]]></content:encoded></item><item><title><![CDATA[Adding Domain-Driven Design to Ports & Adapters - Enriching the Domain Model with Logic]]></title><description><![CDATA[The current codebase, through enriched with stronger types, still is mostly procedural. Let's see how we can combine data and logic to build a much richer domain model.]]></description><link>https://codeartify.substack.com/p/enriching-the-domain-model</link><guid isPermaLink="false">https://codeartify.substack.com/p/enriching-the-domain-model</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 07 Mar 2025 07:00:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e1a214c8-2338-4ced-b33b-880bc52afeb2_2755x1451.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a href="https://codeartify.substack.com/p/domain-model-vs-dtos">previous article</a>, I demonstrated what types of data structures exist and which of those can contain logic. It turns out that most data structures used in various concerns are actually DTOs that are best left devoid of any logic. Only the domain model, which can be placed at the core of the hexagon, should contain the biggest part of the business logic.</p><p>In this article, I want to illustrate how to find logic in a <a href="https://github.com/codeartify/examples/tree/domain-model/src/main/java/com/codeartify/examples/parking_spot_reservation/service">codebase</a> and move it to the domain model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u-Np!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u-Np!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 424w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 848w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1272w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u-Np!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png" width="2137" height="1429" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1429,&quot;width&quot;:2137,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:628127,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff66bea0c-8a49-4711-bcf8-2ba3b17bb5df_2501x1599.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_!u-Np!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 424w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 848w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1272w, https://substackcdn.com/image/fetch/$s_!u-Np!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda8a1b6d-b709-4f50-8733-6abe7f48c9ba_2137x1429.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">The current ports and adapters use case for reserving a parking spot with the domain model at its center.</figcaption></figure></div><h2>Identifying Logic for the Domain Model</h2><p>Currently, all the domain model classes contain no logic at all and are therefore <a href="https://martinfowler.com/bliki/AnemicDomainModel.html">anaemic data classes</a>, a <a href="https://refactoring.guru/smells/data-class">code smell</a> in OOP. </p><p>An indication for displaced logic that should be moved into the domain model can be found when we investigate <em>which classes</em> access the getters from that anaemic domain model to perform some logic like validation, formatting, or more complex manipulations on that data. </p><p>Depending on the context and concern these classes are defined in, such direct data access can be considered a code smell called <em><a href="https://refactoring.guru/smells/feature-envy">Feature Envy</a></em>, meaning that <em>a class is</em> <em>envious of the features (e.g. data, state) another class provides</em>. This access creates a tight coupling between the two classes. </p><p>To increase cohesion and reduce coupling, the logic applied on that data can often be isolated in an own method and moved to the accessed class, as shown below.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HG5u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HG5u!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 424w, https://substackcdn.com/image/fetch/$s_!HG5u!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 848w, https://substackcdn.com/image/fetch/$s_!HG5u!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 1272w, https://substackcdn.com/image/fetch/$s_!HG5u!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HG5u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:413914,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12f330f1-7459-4ebe-8790-e0f5067ce7dd_2012x1987.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!HG5u!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 424w, https://substackcdn.com/image/fetch/$s_!HG5u!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 848w, https://substackcdn.com/image/fetch/$s_!HG5u!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 1272w, https://substackcdn.com/image/fetch/$s_!HG5u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0644fe16-4164-43cc-b95f-a2b235c175bf_2012x1723.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">The envious class accesses the features of another class to perform some logic on it. In some specific cases, this logic should be untangled and extracted into a separate method and moved either into the accessed class.</figcaption></figure></div><p>In procedural code, we often first need to untangle some cohesive logic and extract it into a separate method before moving it from the envious to the accessed class. </p><p>What we can typically see as soon as we <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">extract a method</a> containing the accessed class is that the accessed class is part of the parameter list of this method. </p><p>Such parameter objects are possible targets to move the method to, especially if there is only one parameter.</p><h2><strong>Honour the Concern- and Dependency Rules!</strong></h2><p>Before we move methods into other classes however, we need to be careful not to break <em>concern- and dependency rules</em>. </p><p>Logic should mainly be moved around <em>within</em> a concern. As soon as we <em>cross</em> <em>concern boundaries</em>, we risk that logic ends up in the wrong place.</p><p>For example, presentation logic should not all of a sudden end up in the business concern just because the presentation controller adapter accesses many fields of an application-concern data structure or domain model to create its output JSON. </p><p>The same is true about moving translation logic from the data-access concern into the hexagon&#8217;s core. The domain class should not know how it is translated to a DB entity and thus, this logic should remain within the data-access adapter.</p><p>For our purpose of creating a rich domain model, this means that logic can only be moved from the application concern into the domain model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Uhz1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Uhz1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 424w, https://substackcdn.com/image/fetch/$s_!Uhz1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 848w, https://substackcdn.com/image/fetch/$s_!Uhz1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 1272w, https://substackcdn.com/image/fetch/$s_!Uhz1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Uhz1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png" width="1919" height="1649" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1649,&quot;width&quot;:1919,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:482022,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0de17a34-60b8-45d1-93d7-e4d94bea1505_1919x2083.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_!Uhz1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 424w, https://substackcdn.com/image/fetch/$s_!Uhz1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 848w, https://substackcdn.com/image/fetch/$s_!Uhz1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.png 1272w, https://substackcdn.com/image/fetch/$s_!Uhz1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76257d39-b7b9-4aa0-9d0c-2fe4b1bbbed2_1919x1649.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><figcaption class="image-caption">Avoid logic crossing concern boundaries! Only move logic within the same concern. Don&#8217;t push logic specific to presentation- or data-access concerns into the core application concern.</figcaption></figure></div><h1>Example Refactoring</h1><h3>Validation Logic in the Service</h3><p>Let&#8217;s have a look at the following code snippet taken from the <a href="https://github.com/codeartify/examples/blob/domain-model/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">codebase</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!taAt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!taAt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 424w, https://substackcdn.com/image/fetch/$s_!taAt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 848w, https://substackcdn.com/image/fetch/$s_!taAt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 1272w, https://substackcdn.com/image/fetch/$s_!taAt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!taAt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png" width="1456" height="551" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/effb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:551,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:185694,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.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_!taAt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 424w, https://substackcdn.com/image/fetch/$s_!taAt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 848w, https://substackcdn.com/image/fetch/$s_!taAt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.png 1272w, https://substackcdn.com/image/fetch/$s_!taAt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feffb70e5-d035-477c-930b-4bf93f5bf146_1954x740.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>We see a lot of logic to ensure that the ReservationPeriod is in a valid state before we can process the reservation request any further. </p><p>This piece of logic does not require and additional call to another system and can be done completely in isolation. All it does is accessing the ReservationPeriod&#8217;s startTime and endTime. It is therefore a great candidate to be moved into the actual ReservationPeriod class.</p><p>In fact, we could restructure the code a bit to validate startTime and endTime when we create the ReservationPeriod. The following video illustrates this refactoring.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;9809e851-2904-47db-8bb3-607ddcd3add8&quot;,&quot;duration&quot;:null}"></div><ol><li><p>Start by temporarily extracting startTime and endTime into separate local variables so that the code block does not contain any strong type anymore. </p></li><li><p>Wrap the constructor of ReservationPeriod into a static <a href="https://stackoverflow.com/questions/26444274/creation-method-vs-factory-method">creation method</a> such that we can only create a new ReservationPeriod through that method.</p></li><li><p>Copy-paste the logic into that creation method (together with any constants defined in the service class that are only accessed by that logic).</p></li><li><p>Remove the logic from the service method.</p></li></ol><p>We can further improve the creation methods readability by solving the <em><a href="https://luzkan.github.io/smells/complicated-boolean-expression">Complicated Boolean Expression</a> </em>code smells through the introduction of two intention-revealing static query methods, <em>shorterThanMinimalReservationDuration</em> (and rename the corresponding exception), and <em>outsideOperatingHours</em>, which allows us to remove the one-line <em><a href="https://open.oregonstate.education/setextbook/chapter/code-smells/">redundant and obsolete comment</a> </em>code smells that were present before:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W6v1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W6v1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 424w, https://substackcdn.com/image/fetch/$s_!W6v1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 848w, https://substackcdn.com/image/fetch/$s_!W6v1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 1272w, https://substackcdn.com/image/fetch/$s_!W6v1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W6v1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png" width="1456" height="1055" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1055,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:323712,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.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_!W6v1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 424w, https://substackcdn.com/image/fetch/$s_!W6v1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 848w, https://substackcdn.com/image/fetch/$s_!W6v1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.png 1272w, https://substackcdn.com/image/fetch/$s_!W6v1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb30467a0-6613-40d9-b45b-a33f4044d9cf_1866x1352.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><figcaption class="image-caption">Within the creation method, we can extract additional query methods for complicated boolean conditions with domain-specific names.</figcaption></figure></div><h3>Trade-Offs of Domain Model Classes in Port Interfaces</h3><p>However, now we have a bit of am issue that we need to take care of: we need to mitigate the risk of exceptions being thrown outside the try-catch block in the calling controller class:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FpH0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FpH0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 424w, https://substackcdn.com/image/fetch/$s_!FpH0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 848w, https://substackcdn.com/image/fetch/$s_!FpH0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 1272w, https://substackcdn.com/image/fetch/$s_!FpH0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FpH0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png" width="1626" height="618" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:618,&quot;width&quot;:1626,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:195228,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f23e272-30ff-4984-9999-455523524c7c_1626x664.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_!FpH0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 424w, https://substackcdn.com/image/fetch/$s_!FpH0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 848w, https://substackcdn.com/image/fetch/$s_!FpH0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.png 1272w, https://substackcdn.com/image/fetch/$s_!FpH0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1faaa00-b0ee-4dff-b5c3-1a43f4073d8f_1626x618.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><figcaption class="image-caption">Creating value objects of the domain model inside the controller comes with the additional challenge of handling any exception that can be thrown on creation of any of the domain classes accordingly in the controller.</figcaption></figure></div><p>This is one of the trade-offs of exposing complex domain model classes in port interfaces. Even though we can spare one translation step by avoiding an additional application-specific port DTO to map to and from, we now need to take care of the correct error handling outside the hexagon.</p><p>We could also have saved one translation step if we used the presentation concern&#8217;s request DTO inside the ForReservingParkingSpots port, but then we would again have had the application concern depend on the presentation concern, which we want to avoid for several reasons discussed in earlier articles.</p><p>Alternatively, we could think about simply passing the three parameters startTime, endTime, and reservingMember as primitive types into the port again and moving the creation of ReservationDetails into the port-implementing service. Again, this leads to the <a href="https://refactoring.guru/smells/data-clumps">Data Clump</a> code smell described in an earlier article.</p><p>Conclusively, we need to honour the dependency rules and at the same time avoid excessive translation between data structures containing exactly the same fields. </p><p>In this example, we can mitigate the exception-handling issues by introducing an additional creation method on the ReservationDetails class that only takes primitive data types and returns the final ReservationDetails object.</p><p>This hides away the details of how it is created and reduces the additional potential exception handling cases to one line:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8fYs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8fYs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 424w, https://substackcdn.com/image/fetch/$s_!8fYs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 848w, https://substackcdn.com/image/fetch/$s_!8fYs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 1272w, https://substackcdn.com/image/fetch/$s_!8fYs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8fYs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png" width="1456" height="449" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:449,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:150254,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.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_!8fYs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 424w, https://substackcdn.com/image/fetch/$s_!8fYs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 848w, https://substackcdn.com/image/fetch/$s_!8fYs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.png 1272w, https://substackcdn.com/image/fetch/$s_!8fYs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb31a04c6-9101-4fb8-a530-769a0d8223b4_1886x582.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><figcaption class="image-caption">Moving creation logic for ReservationDetails into the class.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Rwa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Rwa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 424w, https://substackcdn.com/image/fetch/$s_!_Rwa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 848w, https://substackcdn.com/image/fetch/$s_!_Rwa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 1272w, https://substackcdn.com/image/fetch/$s_!_Rwa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Rwa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png" width="1456" height="364" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:364,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:139031,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.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_!_Rwa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 424w, https://substackcdn.com/image/fetch/$s_!_Rwa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 848w, https://substackcdn.com/image/fetch/$s_!_Rwa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 1272w, https://substackcdn.com/image/fetch/$s_!_Rwa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7a7e9b-ce16-4a05-87a2-875804b1e635_1834x458.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The controller now only needs to take care of one line of additional exception-throwing code.</figcaption></figure></div><p>The video shows the refactoring:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;dea9343b-300e-401c-abc9-a0b94159eabe&quot;,&quot;duration&quot;:null}"></div><h3>Increasing Expressiveness of the Domain Model</h3><p>An additional refactoring that may seem an overkill initially is to wrap the Reservation class&#8217;s constructor into a more domain-specific creation method. </p><p>In the real world, we could be talking about &#8220;scheduling a reservation&#8221;. This is information that needs to be inquired from the domain experts and is part of the <a href="https://martinfowler.com/bliki/BoundedContext.html">ubiquitous language of that specific bounded context</a>. A good name for that creation method could be <em>schedule</em>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RA6Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RA6Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 424w, https://substackcdn.com/image/fetch/$s_!RA6Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 848w, https://substackcdn.com/image/fetch/$s_!RA6Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 1272w, https://substackcdn.com/image/fetch/$s_!RA6Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RA6Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png" width="1456" height="887" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:887,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:260307,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.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_!RA6Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 424w, https://substackcdn.com/image/fetch/$s_!RA6Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 848w, https://substackcdn.com/image/fetch/$s_!RA6Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.png 1272w, https://substackcdn.com/image/fetch/$s_!RA6Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1b03d5f-6cab-49a3-9040-ac79db89bfd3_1846x1124.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><figcaption class="image-caption">Reservation.schedule closer represents the real-world language to create a new reservation.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jU7A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jU7A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 424w, https://substackcdn.com/image/fetch/$s_!jU7A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 848w, https://substackcdn.com/image/fetch/$s_!jU7A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 1272w, https://substackcdn.com/image/fetch/$s_!jU7A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jU7A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png" width="1456" height="441" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:441,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121676,&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://codeartify.substack.com/i/157614727?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.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_!jU7A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 424w, https://substackcdn.com/image/fetch/$s_!jU7A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 848w, https://substackcdn.com/image/fetch/$s_!jU7A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.png 1272w, https://substackcdn.com/image/fetch/$s_!jU7A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca8265d-b689-4a75-b4e3-08b24b07abbc_1738x526.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><figcaption class="image-caption">Currently, schedule is simply a wrapper method that could be enhanced with additional validation logic.</figcaption></figure></div><p>You can find the refactored codebase <a href="https://github.com/codeartify/examples/blob/feature-envy/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">here</a>.</p><h2>Conclusion</h2><p>In this article, I have demonstrated how feature envy can show us where logic may be displaced, and how we can build up a richer domain model by wrapping parts of that logic into own methods and moving them into these classes.</p><p>Furthermore, I showed how domain-specific creation methods help to hide away the complexity of how domain model classes are internally structured and created, further improving maintainability and providing a place to put validation logic.</p><p>I have also illustrated how each decision comes with trade-offs and need to be weighed against each other. Being proficient in the <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">refactoring tools the IDE provides</a> is therefore inevitable or else, the codebase may remain in suboptimal conditions.</p><p>The more we separate logic into smaller pieces and move them closer to the data they  use, the clearer the entire domain becomes. This can also lead to breakthroughs in understanding, something not possible if we keep the code in a procedural or technically convoluted state. </p><p>Now that the domain model already contains some logic, I will explore how to move from Hexagonal to Clean Architecture. Subscribe if you don&#8217;t want to miss it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p><p>To effectively learn how to identify code smells and refactor them, check out our workshop on <a href="https://codeartify.com/en/courses/clean-code-workshop">Clean Code</a>.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Adding Domain-Driven Design to Ports and Adapters - Rich Domain Model vs. DTOs]]></title><description><![CDATA[In this article, I will discuss what types of data structures exist and which ones should contain business logic contributing to a rich domain model and which should remain anaemic data structures.]]></description><link>https://codeartify.substack.com/p/domain-model-vs-dtos</link><guid isPermaLink="false">https://codeartify.substack.com/p/domain-model-vs-dtos</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 28 Feb 2025 07:01:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ebe8aef3-03d2-45bb-ab42-dcd5f4ce37b4_2755x1451.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a href="https://codeartify.substack.com/p/adding-domain-driven-design-to-ports">previous article</a>, I illustrated how we can increase expressiveness of ports by replacing low-level primitive types with higher-level, context- and domain-specific types. </p><p>However, these data structures initially simply wrap some co-dependent data and do not much else. If we want to improve the expressiveness of our software, we need to find logic that belongs to these data structures and move it closer to them.</p><p>A couple of questions regarding data structures need to be answered before we can start moving logic into classes, which I will discuss in the following:</p><ul><li><p>Which data structures are pure data transfer objects (and thus, devoid of logic)?</p></li><li><p>Which data structures can contain logic?</p></li><li><p>Which data structures can be used in port interfaces? </p></li></ul><p>Let&#8217;s focus on the highlighted classes in the diagram below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A9Fj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A9Fj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 424w, https://substackcdn.com/image/fetch/$s_!A9Fj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 848w, https://substackcdn.com/image/fetch/$s_!A9Fj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 1272w, https://substackcdn.com/image/fetch/$s_!A9Fj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A9Fj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png" width="2209" height="1336" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3f04275-812a-4505-82b0-d608c1002297_2209x1336.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1336,&quot;width&quot;:2209,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:477293,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba6a0cda-05d0-4a68-9a2f-42e22e30ef3e_2631x1519.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_!A9Fj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 424w, https://substackcdn.com/image/fetch/$s_!A9Fj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 848w, https://substackcdn.com/image/fetch/$s_!A9Fj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 1272w, https://substackcdn.com/image/fetch/$s_!A9Fj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f04275-812a-4505-82b0-d608c1002297_2209x1336.png 1456w" sizes="100vw" fetchpriority="high"></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>In the presentation concern, there are two classes ParkingReservationRequest and - Response. </p><p>Inside the hexagon, there are ReservationDetails, ReservationId, ReservationPeriod, Reservation, ParkingSpot, and ReservingMember. </p><p>In the data-access concern, there are ParkingSpotDBEntity and ParkingReservationDBEntity. </p><p>Which of these are pure DTOs, can contain logic, and can be used in port interfaces?</p><h2>Pure Data Transfer Objects</h2><p>Anything that represents pure data should not contain any logic at all. </p><h3>Presentation-Concern Data Structures</h3><p>ParkingReservationRequest and -Response are simply class representations of JSON data structures. Thus, these two classes should only contain getters, setters, and constructors, along with utility functions like hash code or equals and toString. No mapping or business logic should be part of these classes.</p><h3>Data-Access-Concern Data Structures</h3><p>The same logic applies to the data structures on the data-access side. Both ParkingReservationDBEntity and ParkingSpotDBEntity simply represent a database table row. They are <em>not</em> business entities and should <em>not</em> contain any business logic either, as this would entangle the two concerns. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WueK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WueK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 424w, https://substackcdn.com/image/fetch/$s_!WueK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 848w, https://substackcdn.com/image/fetch/$s_!WueK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 1272w, https://substackcdn.com/image/fetch/$s_!WueK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WueK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png" width="1623" height="1299" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1299,&quot;width&quot;:1623,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:349073,&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://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36354fea-f982-478d-887d-feb4fdc92792_2026x1974.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_!WueK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 424w, https://substackcdn.com/image/fetch/$s_!WueK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 848w, https://substackcdn.com/image/fetch/$s_!WueK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.png 1272w, https://substackcdn.com/image/fetch/$s_!WueK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d4ffb31-e8bc-4424-b344-69a9d90a0861_1623x1299.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><figcaption class="image-caption">Presentation- and data-access-concern data structures should not contain any logic and be treated as pure DTOs.</figcaption></figure></div><h2>Data with Logic - the Domain Model</h2><p>What we often refer to as the <em>domain model </em>in Domain-Driven Design are actually the data structures used inside the core of the hexagon to achieve some business goal.</p><p>These data structures are magnets for business logic and should therefore be used exactly for that - building up a rich domain model with functionality on the classes that make sense in the specific domain they&#8217;re used. </p><p>In Domain-Driven Design, there are three domain model types:</p><ol><li><p>Value Objects / Values</p></li><li><p>Entities</p></li><li><p>Aggregates</p></li></ol><p>Value objects, or simply Values, are context-specific objects without an identity, like for example an ID, FirstName, or Dollar. If two objects have the same values, they are treated like they were the same. They contain business logic for validation, such that they are never in an invalid state, or formatting like a PhoneNumber that can be queried for a local or international format.</p><p>Entities, on the other hand, are objects that have an identity. Two entities with the same values are only the same if their identifier, for example an ID value object, are the same. Entities contain value objects or other entities. </p><p>Entities should also use value objects as internal fields. Primitive types should only be used when domain constraints aren&#8217;t required. When in doubt, it's better to introduce a value object and later discard it than to miss an important domain constraint.</p><p>Aggregates are entities that cluster other entities and value objects so that each aggregate can be treated as a whole. Aggregates provide a <em>transactional boundary<strong> </strong></em>to avoid inconsistent states. Any change to any of the internal entities can only be done through the aggregate&#8217;s methods and the internal entities should never be exposed and manipulated outside of their aggregate. </p><p>In the context, the domain model could look as follows: </p><p>ReservationDetails, -Id, -Period, and ReservingMember are value objects. </p><p>ParkingSpot would be an entity or an aggregate, but because it is currently just an ID,  we could rename it to ParkingSpotId and consider it a value object as well. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xyGY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xyGY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 424w, https://substackcdn.com/image/fetch/$s_!xyGY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 848w, https://substackcdn.com/image/fetch/$s_!xyGY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 1272w, https://substackcdn.com/image/fetch/$s_!xyGY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xyGY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png" width="670" height="75" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5515fed1-5064-482d-9f08-6372f67254c4_670x75.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:75,&quot;width&quot;:670,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14591,&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://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb45ddb90-1a02-4b49-a37e-5be4aa3e7264_670x82.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_!xyGY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 424w, https://substackcdn.com/image/fetch/$s_!xyGY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 848w, https://substackcdn.com/image/fetch/$s_!xyGY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 1272w, https://substackcdn.com/image/fetch/$s_!xyGY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515fed1-5064-482d-9f08-6372f67254c4_670x75.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Renaming ParkingSpot to ParkingSpotId to reflect the actual nature of the class.</figcaption></figure></div><p>The only aggregate we can see here is <em>Reservation</em>, but it currently lacks a dedicated ID every aggregate should be assigned when it&#8217;s created. Currently, ReservationId is only created when the Reservation aggregate is stored. Such an ID is tied to persistence concerns rather than the domain model. In a future article, we will replace it with a domain-specific, independent ID. If you don&#8217;t want to miss the article where I will do that, simply subscribe here:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p><p>Of course, once we start refactoring the logic, we may notice that some definitions change and a value becomes an entity or the other way round. The current preliminary domain model could look as follows:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wRNB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wRNB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 424w, https://substackcdn.com/image/fetch/$s_!wRNB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 848w, https://substackcdn.com/image/fetch/$s_!wRNB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 1272w, https://substackcdn.com/image/fetch/$s_!wRNB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wRNB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png" width="1921" height="1090" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1090,&quot;width&quot;:1921,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:465279,&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://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9ff0379-f03c-4a8b-9dcb-3e70635c75f1_2256x1772.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_!wRNB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 424w, https://substackcdn.com/image/fetch/$s_!wRNB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 848w, https://substackcdn.com/image/fetch/$s_!wRNB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.png 1272w, https://substackcdn.com/image/fetch/$s_!wRNB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fb7e565-e0c0-41ad-bf96-f3626f1cdbce_1921x1090.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><figcaption class="image-caption">A preliminary domain model with Reservation as the aggregate containing several value objects.</figcaption></figure></div><h3>Data Structures in Port Interfaces</h3><p>Even though we could imagine having special DTOs to transfer data between the outside world and the core, which do not expose the internal domain model, in practice, too many translation steps can become cumbersome to maintain and even start to slow down the application significantly.</p><p>Translation should be minimal such that the core is isolated from the surrounding world, but exposing certain internal structures of the domain model in the port interface does not hurt this isolation <em>as long as we keep some rules in mind</em>.</p><p>Let&#8217;s see which domain model classes are unproblematic to expose in port interfaces and which should be avoided under some conditions.</p><h3>Inbound Port Interfaces</h3><p>The transactional-boundary property of aggregates has profound consequences to what data structures can be used in inbound port interfaces: </p><p><em>Never expose <a href="https://martinfowler.com/bliki/DDD_Aggregate.html">Aggregates</a> in inbound ports! </em></p><p>If we expose aggregates in inbound ports, they are outside the transactional boundaries of that port interface. Thus, changing their state outside may have unforeseeable effects, leading to strange and hard to find defects and data inconsistencies.</p><p>On the other hand, value objects pose <em>no problem</em> as they are simply enhanced data structures that are always in a valid state. </p><p>This has advantages because no invalid data structure can be passed into or out of the hexagon. Conclusively,<em> we can use Value Objects in inbound port interfaces instead of unvalidated primitive types.</em></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sf1X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sf1X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 424w, https://substackcdn.com/image/fetch/$s_!Sf1X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 848w, https://substackcdn.com/image/fetch/$s_!Sf1X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 1272w, https://substackcdn.com/image/fetch/$s_!Sf1X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sf1X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png" width="1450" height="160" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:160,&quot;width&quot;:1450,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36267,&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://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F662bd698-0698-4160-bd10-dd7f8df26594_1450x166.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_!Sf1X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 424w, https://substackcdn.com/image/fetch/$s_!Sf1X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 848w, https://substackcdn.com/image/fetch/$s_!Sf1X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 1272w, https://substackcdn.com/image/fetch/$s_!Sf1X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32faf6fa-a2b1-44a1-b657-b863708b4ff3_1450x160.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The inbound port interface only exposes values, not aggregates.</figcaption></figure></div><h3>Outbound Port Interfaces</h3><p>Outbound port interfaces behave differently than inbound ports. They are used always within the transactional boundaries of the hexagon. Aggregates are &#8220;data storage units&#8221;. Even though they are not part of the data-access concern, they should only be used in CRUD <em>repository</em> interfaces that are used to store and retrieve aggregates. </p><p>It could be tempting to use aggregates for other purposes, e.g. if we want to send a message that requires some or all of the aggregate&#8217;s data. However, aggregates are only safe for repository ports but should not be used in outbound messaging to prevent unintended side effects when consumed by unknown adapters. Instead, we should create a dedicated value object for such cases.</p><p>Such an uni-directional messaging port could be seen similarly to the return value of the inbound port. We don&#8217;t want to expose the internal domain model to anybody else than the dedicated repository adapters and the application-specific service class to avoid unintentional, uncontrollable changes in our data.</p><p>Value objects, on the other hand, can and should be used in all ports. Also a dedicated message object can contain the same value objects as the aggregate. </p><p>On the other hand, never expose <em>non-aggregate entities</em>. Neither in inbound- nor in outbound ports. They are protected by the aggregate they belong to and should only be changed using aggregate methods to ensure data integrity.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VzzM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VzzM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 424w, https://substackcdn.com/image/fetch/$s_!VzzM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 848w, https://substackcdn.com/image/fetch/$s_!VzzM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 1272w, https://substackcdn.com/image/fetch/$s_!VzzM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VzzM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png" width="1278" height="126" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:126,&quot;width&quot;:1278,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26805,&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://codeartify.substack.com/i/157243621?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.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_!VzzM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 424w, https://substackcdn.com/image/fetch/$s_!VzzM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 848w, https://substackcdn.com/image/fetch/$s_!VzzM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 1272w, https://substackcdn.com/image/fetch/$s_!VzzM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46c2f330-cae3-4461-b311-1b97493dc7ea_1278x126.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Outbound repository port interfaces can expose aggregates as they&#8217;re data integrity is protected by the transactional boundaries of the hexagon.</figcaption></figure></div><h2>Exposing the Domain Model?</h2><p>Some may argue that exposing the domain model to the outside world harms encapsulation. This is absolutely true. To circumvent that, we can still create dedicated, application-concern-specific DTOs and use them in our inbound and outbound port interfaces if that makes sense. Or simply use primitive types again. </p><p>We always need to weigh the additional translation / mapping overhead against a more isolated core. As soon as we expose the core domain model in our ports, we give away some of the freedom of changing it independently from the outside world. </p><p>If the core is only used by our team, we may choose such a more relaxed approach. On the other hand, if other teams want to integrate our core as a library, we may hide away the entire internal model and instead pass a simple data structure with primitive types and validate them within. It depends on your context which way you choose.</p><h2>Conclusion</h2><p>I have now illustrated which data structures can contain logic and which not. Furthermore, I showed which of them can be used in which port type.</p><p>If we want to employ a Domain-Driven Design domain model in our core, we should only expose value objects in the inbound port interfaces. </p><p>On the other hand, outbound CRUD repository ports called from within the hexagon can contain both values and aggregates as the transactional boundary is defined around the inbound port interface, shielding the aggregate from dangerous operations that could lead to data inconsistencies. However, aggregates should not be used in non-repository ports to avoid unintentional aggregate manipulation in these adapters.</p><p>Entities should neither be used in inbound- nor outbound ports as they need to be part of an aggregate and only be manipulated using methods defined on that aggregate.</p><p>Now that we know which entities can be used to move logic towards, in the next article I will show how to identify it in code and move it towards the various values and aggregates to build up a rich domain model. </p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p>]]></content:encoded></item><item><title><![CDATA[Adding Domain-Driven Design to Ports & Adapters - Improving Port Interfaces]]></title><description><![CDATA[Currently, I mainly use primitive data types in port interfaces. Let's improve them by introducing parameter objects with concern- and domain-specific names.]]></description><link>https://codeartify.substack.com/p/adding-domain-driven-design-to-ports</link><guid isPermaLink="false">https://codeartify.substack.com/p/adding-domain-driven-design-to-ports</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Fri, 21 Feb 2025 07:01:51 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/480ea9c6-730c-42a7-9abc-b711ea997d07_2755x1451.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a href="https://codeartify.substack.com/p/interface-segregation">last article</a>, I left the <a href="https://github.com/codeartify/examples/tree/interface-segregation/src/main/java/com/codeartify/examples/parking_spot_reservation/service">codebase</a> with a structure that corresponds to the following diagram:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I26T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I26T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 424w, https://substackcdn.com/image/fetch/$s_!I26T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 848w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1272w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I26T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png" width="1456" height="948" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:948,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I26T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 424w, https://substackcdn.com/image/fetch/$s_!I26T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 848w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1272w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">The codebase at the end of the last article, showing a hexagonal architecture with single method port interfaces.</figcaption></figure></div><p>The port interfaces, as shown above using bright blue stickies, look as follows:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NHbi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NHbi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 424w, https://substackcdn.com/image/fetch/$s_!NHbi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 848w, https://substackcdn.com/image/fetch/$s_!NHbi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 1272w, https://substackcdn.com/image/fetch/$s_!NHbi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NHbi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png" width="1611" height="162" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:162,&quot;width&quot;:1611,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:40014,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NHbi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 424w, https://substackcdn.com/image/fetch/$s_!NHbi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 848w, https://substackcdn.com/image/fetch/$s_!NHbi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 1272w, https://substackcdn.com/image/fetch/$s_!NHbi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09b18214-4c34-4b63-a3d3-16621c6daaf7_1611x162.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">Inbound port into the application.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!erAL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!erAL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 424w, https://substackcdn.com/image/fetch/$s_!erAL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 848w, https://substackcdn.com/image/fetch/$s_!erAL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 1272w, https://substackcdn.com/image/fetch/$s_!erAL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!erAL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png" width="1456" height="105" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:105,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32434,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!erAL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 424w, https://substackcdn.com/image/fetch/$s_!erAL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 848w, https://substackcdn.com/image/fetch/$s_!erAL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 1272w, https://substackcdn.com/image/fetch/$s_!erAL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9a352e6-bcec-4aa9-976d-dd3bab2b2121_1688x122.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L5tv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L5tv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 424w, https://substackcdn.com/image/fetch/$s_!L5tv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 848w, https://substackcdn.com/image/fetch/$s_!L5tv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 1272w, https://substackcdn.com/image/fetch/$s_!L5tv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L5tv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png" width="1456" height="93" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:93,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33309,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L5tv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 424w, https://substackcdn.com/image/fetch/$s_!L5tv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 848w, https://substackcdn.com/image/fetch/$s_!L5tv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 1272w, https://substackcdn.com/image/fetch/$s_!L5tv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09e18f7b-9b58-4676-9827-8642fd8f2dd0_1880x120.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KgWW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KgWW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 424w, https://substackcdn.com/image/fetch/$s_!KgWW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 848w, https://substackcdn.com/image/fetch/$s_!KgWW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 1272w, https://substackcdn.com/image/fetch/$s_!KgWW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KgWW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png" width="1456" height="115" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:115,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36077,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KgWW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 424w, https://substackcdn.com/image/fetch/$s_!KgWW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 848w, https://substackcdn.com/image/fetch/$s_!KgWW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 1272w, https://substackcdn.com/image/fetch/$s_!KgWW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e8f9848-45f8-48c6-ba84-ea15de7e7eb3_1694x134.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">Outbound ports for interaction of the application with the outside world.</figcaption></figure></div><h2>Primitive Types in Port Interfaces</h2><p>The port interfaces, apart from the ParkingSpot class, currently are intentionally left  <em>primitive</em> to emphasise the fact that hexagonal architecture does not prescribe any format, just that the outside world depends on the inside application and not the other way round. </p><p>I refer to <em>primitive types</em> not only for the classic low-level types like <em>int, long, double, char,</em> etc., but also to those types that are not associated with any of the different concerns. They could be used in any concern without creating a dependency between them.</p><p>This means that I also consider <em>string</em>- or <em>collection</em> types like <em>lists, sets,</em> or <em>maps</em>, or <em>date</em>-related types to be <em>primitive</em> types. They can be used in any generic context and do not convey any additional meaning beyond. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6--E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6--E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 424w, https://substackcdn.com/image/fetch/$s_!6--E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 848w, https://substackcdn.com/image/fetch/$s_!6--E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 1272w, https://substackcdn.com/image/fetch/$s_!6--E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6--E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png" width="2104" height="1343" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/efc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1343,&quot;width&quot;:2104,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:341217,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6--E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 424w, https://substackcdn.com/image/fetch/$s_!6--E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 848w, https://substackcdn.com/image/fetch/$s_!6--E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.png 1272w, https://substackcdn.com/image/fetch/$s_!6--E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3e393-4f95-45d5-b133-14764502d0ce_2104x1343.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><figcaption class="image-caption">Primitive types can also be stronger language-specific types that lack any concern-specific meaning.</figcaption></figure></div><p>However, from a software design perspective, primitive types can cause issues. </p><p>Data passed back and fourth through adapters typically belongs together to some extent. Thus, they form a code smell called <em><a href="https://refactoring.guru/smells/data-clumps">Data Clump</a></em>, a special case of <em><a href="https://refactoring.guru/smells/primitive-obsession">Primitive Obsession</a>.</em> Such primitive types lack validation and can therefore easily be passed in an invalid state, which makes an unchecked usage of them problematic.</p><p>Because of Data Clumps, the port signature is also longer than it should be, which is described by the <em><a href="https://refactoring.guru/smells/long-parameter-list">Long Parameter List</a> </em>code smell. Having many primitive parameters of the same type can easily lead to a mix up, hard to read code, and code that has to be adapted in many places if the parameter list changes.</p><p>The immediate solution to these problems is to create a stronger type with a higher-level meaning. So let&#8217;s do exactly that. I try to use concern-specific names - this means that the names of types used within the hexagon, which contains only business concerns, will also get names that have a meaning in the real-world domain for which the system is built, moving the system towards <a href="https://martinfowler.com/bliki/DomainDrivenDesign.html">Domain-Driven Design</a>.</p><h2>Introducing Stronger Types into Port Interfaces</h2><p>I use IntelliJ to <a href="https://refactoring.guru/introduce-parameter-object">Introduce Parameter Objects</a>. This refactoring automatically replaces the selected parameters with an object containing the parameters as fields.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YVlH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YVlH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 424w, https://substackcdn.com/image/fetch/$s_!YVlH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 848w, https://substackcdn.com/image/fetch/$s_!YVlH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 1272w, https://substackcdn.com/image/fetch/$s_!YVlH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YVlH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png" width="1382" height="1646" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1646,&quot;width&quot;:1382,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:274655,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YVlH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 424w, https://substackcdn.com/image/fetch/$s_!YVlH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 848w, https://substackcdn.com/image/fetch/$s_!YVlH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.png 1272w, https://substackcdn.com/image/fetch/$s_!YVlH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb162ae81-f090-4c15-ac44-dd540876decb_1382x1646.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><figcaption class="image-caption">IDE&#8217;s like IntelliJ provide refactoring tools to introduce parameter objects easily. Just select the parameters that belong together and create or reuse a class to wrap them.</figcaption></figure></div><h3>Stronger Types in Inbound Ports</h3><p>I start with the inbound port ForReservingParkingSpots. Initially, I simply summarise the 3 parameters startTime, endTime, and reservingMember into a wrapper class called <em>ReservationDetails</em> that I place into the application concern. </p><p>The presentation concern (the controller adapter) needs to translate the data to this input object to be able to communicate with the application. Importantly, ReservationDetails itself is a POJO free of any data-access- or presentation-concern structures like JSON or @Entity annotations, as this would violate the dependency rule. Only generic language extensions like Lombok (constructors, getters, setters) should be used for these classes.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Unp2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Unp2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 424w, https://substackcdn.com/image/fetch/$s_!Unp2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 848w, https://substackcdn.com/image/fetch/$s_!Unp2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 1272w, https://substackcdn.com/image/fetch/$s_!Unp2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Unp2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png" width="1456" height="141" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:141,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37697,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Unp2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 424w, https://substackcdn.com/image/fetch/$s_!Unp2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 848w, https://substackcdn.com/image/fetch/$s_!Unp2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 1272w, https://substackcdn.com/image/fetch/$s_!Unp2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87cc362a-6f26-4df1-a1c1-7434a2778f94_1710x166.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tz4L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tz4L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 424w, https://substackcdn.com/image/fetch/$s_!Tz4L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 848w, https://substackcdn.com/image/fetch/$s_!Tz4L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 1272w, https://substackcdn.com/image/fetch/$s_!Tz4L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tz4L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png" width="1456" height="53" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:53,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22722,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Tz4L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 424w, https://substackcdn.com/image/fetch/$s_!Tz4L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 848w, https://substackcdn.com/image/fetch/$s_!Tz4L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 1272w, https://substackcdn.com/image/fetch/$s_!Tz4L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb2b8a2f-9c59-434c-8feb-226cb3cbec5c_1742x64.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Stronger Types in Outbound Ports</h3><p>I can do the same with outbound port interfaces. For example, I can reuse the ReservationDetails object in the hasActivateReservation method like below:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8hSw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8hSw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 424w, https://substackcdn.com/image/fetch/$s_!8hSw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 848w, https://substackcdn.com/image/fetch/$s_!8hSw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 1272w, https://substackcdn.com/image/fetch/$s_!8hSw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8hSw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png" width="1456" height="112" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:112,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33052,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8hSw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 424w, https://substackcdn.com/image/fetch/$s_!8hSw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 848w, https://substackcdn.com/image/fetch/$s_!8hSw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 1272w, https://substackcdn.com/image/fetch/$s_!8hSw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc896e066-7d4d-41c5-86fe-ff6027f2ed90_1720x132.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And ForStoringReservations gets a Reservation class as its parameter:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L7Kl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L7Kl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 424w, https://substackcdn.com/image/fetch/$s_!L7Kl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 848w, https://substackcdn.com/image/fetch/$s_!L7Kl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 1272w, https://substackcdn.com/image/fetch/$s_!L7Kl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L7Kl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png" width="1456" height="108" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:108,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29504,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L7Kl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 424w, https://substackcdn.com/image/fetch/$s_!L7Kl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 848w, https://substackcdn.com/image/fetch/$s_!L7Kl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 1272w, https://substackcdn.com/image/fetch/$s_!L7Kl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F013aa7f7-85f5-43d2-8ff5-7e7569846dc3_1856x138.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cI0p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cI0p!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 424w, https://substackcdn.com/image/fetch/$s_!cI0p!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 848w, https://substackcdn.com/image/fetch/$s_!cI0p!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 1272w, https://substackcdn.com/image/fetch/$s_!cI0p!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cI0p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png" width="1456" height="41" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:41,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24004,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cI0p!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 424w, https://substackcdn.com/image/fetch/$s_!cI0p!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 848w, https://substackcdn.com/image/fetch/$s_!cI0p!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 1272w, https://substackcdn.com/image/fetch/$s_!cI0p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3d1f8b2-9087-4bea-856b-751ca0706695_1918x54.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Furthermore, I can also reuse the ReservationDetails class in Reservation&#8217;s constructor:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D8F-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D8F-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 424w, https://substackcdn.com/image/fetch/$s_!D8F-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 848w, https://substackcdn.com/image/fetch/$s_!D8F-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 1272w, https://substackcdn.com/image/fetch/$s_!D8F-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D8F-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png" width="1394" height="50" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:50,&quot;width&quot;:1394,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20131,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D8F-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 424w, https://substackcdn.com/image/fetch/$s_!D8F-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 848w, https://substackcdn.com/image/fetch/$s_!D8F-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 1272w, https://substackcdn.com/image/fetch/$s_!D8F-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faac08e10-e193-4d2d-a273-2cc72b255c8c_1394x50.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>Additional Stronger Types</h2><p>ReservationDetails can be further separated. For example, startTime and endTime always go together and there is no possibility to have a startTime without and endTime and vice versa. Thus, I add an additional class called <em>ReservationPeriod </em>that summarises the two. </p><p>Furthermore, the reservingMember string does not have any validation yet. By creating a new class ReservingMember, I can introduce a place that potentially covers that validation later and further improves expressiveness of that port.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XMV9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XMV9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 424w, https://substackcdn.com/image/fetch/$s_!XMV9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 848w, https://substackcdn.com/image/fetch/$s_!XMV9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 1272w, https://substackcdn.com/image/fetch/$s_!XMV9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XMV9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png" width="1456" height="184" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:184,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44866,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XMV9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 424w, https://substackcdn.com/image/fetch/$s_!XMV9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 848w, https://substackcdn.com/image/fetch/$s_!XMV9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 1272w, https://substackcdn.com/image/fetch/$s_!XMV9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabee8b81-dc2d-4106-b5d4-22ca3818f5af_1708x216.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>Return Values</h2><p>On the return-value side, we see that a Long value is returned in both ForStoringReservations and ForReservingParkingSpots. This is suboptimal because we can only guess its meaning from the interface signature. Having a stronger type <em>ReservationId</em> immediately reveals its intent.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4vN7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4vN7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 424w, https://substackcdn.com/image/fetch/$s_!4vN7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 848w, https://substackcdn.com/image/fetch/$s_!4vN7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 1272w, https://substackcdn.com/image/fetch/$s_!4vN7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4vN7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png" width="1250" height="440" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:440,&quot;width&quot;:1250,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!4vN7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 424w, https://substackcdn.com/image/fetch/$s_!4vN7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 848w, https://substackcdn.com/image/fetch/$s_!4vN7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.png 1272w, https://substackcdn.com/image/fetch/$s_!4vN7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63927211-49dd-481e-b239-5bf94d9dc678_1250x440.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>Translating Data Structures Between Concerns</h2><p>Of course, we also need to adapt the translation between the models in the adapters and service. This is the strong part of Ports and Adapters - we can build the internal model of the hexagon without having to directly consider the outside world. The adapters handle such changes and act as <em><a href="https://ddd-practitioners.com/home/glossary/bounded-context/bounded-context-relationship/anticorruption-layer/">Anti-Corruption Layer</a></em>, allowing the internal model to evolve on its own.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W9MJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W9MJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 424w, https://substackcdn.com/image/fetch/$s_!W9MJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 848w, https://substackcdn.com/image/fetch/$s_!W9MJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 1272w, https://substackcdn.com/image/fetch/$s_!W9MJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W9MJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png" width="1456" height="536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:536,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:201587,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!W9MJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 424w, https://substackcdn.com/image/fetch/$s_!W9MJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 848w, https://substackcdn.com/image/fetch/$s_!W9MJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.png 1272w, https://substackcdn.com/image/fetch/$s_!W9MJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f8489a6-f823-447b-8ca5-985c652e0b20_2032x748.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><figcaption class="image-caption">The ParkingReservationRepositoryAdapter handles the back and forth translation of the hexagon&#8217;s internal model and the database entities.</figcaption></figure></div><p>The current solution can be found on the branch <a href="https://github.com/codeartify/examples/tree/stronger-types/src/main/java/com/codeartify/examples/parking_spot_reservation/service">stronger-types</a>.</p><h2>Conclusion</h2><p>In this article, I have laid out why primitive types can hurt expressiveness, and how stronger types can make port interfaces much easier to read and comprehend without having to dive in deep into the actual implementation.</p><p>The introduced data structures are all part of the business concern and can therefore be used not only by that, but also by the adapters to translate between the internal and the external model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DhMV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DhMV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 424w, https://substackcdn.com/image/fetch/$s_!DhMV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 848w, https://substackcdn.com/image/fetch/$s_!DhMV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 1272w, https://substackcdn.com/image/fetch/$s_!DhMV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DhMV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png" width="1456" height="846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:672561,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DhMV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 424w, https://substackcdn.com/image/fetch/$s_!DhMV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 848w, https://substackcdn.com/image/fetch/$s_!DhMV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.png 1272w, https://substackcdn.com/image/fetch/$s_!DhMV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cac6019-f928-42f0-a5d1-78827e6c783c_2624x1524.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>However, there are some restrictions and considerations when it comes to exposing data structures from the business concern outside of the hexagon which I will explore in the next article.</p><p>Additionally, the types currently are simple data holders without any additional logic associated with them. In the next article, I will also discuss which data structures should remain such simple DTOs, and which on the other hand could be used to build up a rich domain model. Subscribe if you don&#8217;t want to miss it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p><h2></h2>]]></content:encoded></item><item><title><![CDATA[Towards Hexagonal Architecture - Interface Segregation]]></title><description><![CDATA[After examining driven ports for data-access separation and dependency inversion, I will take a closer look at interface segregation, ports on the driver side, and port naming.]]></description><link>https://codeartify.substack.com/p/interface-segregation</link><guid isPermaLink="false">https://codeartify.substack.com/p/interface-segregation</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Tue, 04 Feb 2025 07:02:11 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/47d1c836-a56d-4b6a-bc40-6b9ca33d83ca_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the last <a href="https://codeartify.substack.com/p/dependency-inversion">article</a>, I showed how to introduce ports on the &#8220;driven&#8221; (right) side of the hexagon to effectively invert the dependencies between data-access and business concerns, such that the first depends on the latter completely and there is no data-access reference anymore in the business application service. The following diagram illustrates the <a href="https://github.com/codeartify/examples/blob/introducing-data-access-interfaces/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">code</a>&#8217;s current structure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5-ZB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5-ZB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 424w, https://substackcdn.com/image/fetch/$s_!5-ZB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 848w, https://substackcdn.com/image/fetch/$s_!5-ZB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 1272w, https://substackcdn.com/image/fetch/$s_!5-ZB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5-ZB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png" width="2752" height="1799" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1799,&quot;width&quot;:2752,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1049383,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5-ZB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 424w, https://substackcdn.com/image/fetch/$s_!5-ZB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 848w, https://substackcdn.com/image/fetch/$s_!5-ZB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 1272w, https://substackcdn.com/image/fetch/$s_!5-ZB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c52e445-2977-4812-9305-a36ca32de8bd_2752x1799.png 1456w" sizes="100vw" fetchpriority="high"></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>The &#8220;driven&#8221; side, which is called that way because it is <em>driven</em> by the application service as indicated by the vertical line inside the hexagon, now obeys the rules of Ports and Adapters. But are there still adaptations needed to be able to talk of a real &#8220;hexagonal architecture&#8221;? </p><h2>Interface Segregation Port on the Presentation Side</h2><p>Indeed, if we look at the &#8220;driving&#8221; side, meaning the left side of the diagonal in the diagram from where the application is called, we can see that there is still a direct dependency from the controller to the application service.</p><p>This is not perfect as the application service may expose various public use-case methods that the controller doesn&#8217;t need to know about. </p><p>However, especially during transition phases from a technical service with multiple use-case methods to a cleaner, business-centric structure, it is advisable to first logically split the service into individual use-case methods and then step-by-step split it up physically into smaller services. </p><p>This can be achieved by employing <a href="https://en.wikipedia.org/wiki/Interface_segregation_principle">interface segregation</a> and using these interfaces in place of the actual service within the controller, reminiscent of the <a href="https://martinfowler.com/bliki/StranglerFigApplication.html">strangler-fig pattern</a>. The controller won&#8217;t need to know that behind the scenes, it is actually using a large service. This makes the controller also easier to test, as only one method needs to be stubbed and not an entire service with many methods. </p><p>The resulting structure looks as follows:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xYc1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xYc1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 424w, https://substackcdn.com/image/fetch/$s_!xYc1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 848w, https://substackcdn.com/image/fetch/$s_!xYc1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 1272w, https://substackcdn.com/image/fetch/$s_!xYc1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xYc1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png" width="2766" height="1793" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1793,&quot;width&quot;:2766,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1128268,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xYc1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 424w, https://substackcdn.com/image/fetch/$s_!xYc1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 848w, https://substackcdn.com/image/fetch/$s_!xYc1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.png 1272w, https://substackcdn.com/image/fetch/$s_!xYc1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d963ad-927d-40b9-8616-4ac23e374301_2766x1793.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><figcaption class="image-caption">Adding an interface &#8220;ForReservingParkingSpots&#8221; between controller and service.</figcaption></figure></div><p>Importantly, this interface or port only contains either primitive- or application-specific data structures and no data structures or annotations of the presentation concern (i.e. DTO representations of JSON, XML, etc.) anymore. </p><p>This driving port on the left side of the diagonal in the diagram is <em>used<strong> </strong></em>by the controller and <em>implemented </em>by the application service, which is different from the ports on the right side of the diagonal, which are <em>used</em> by the application service, and <em>implemented<strong> </strong></em>by the data-access adapters.</p><p>Thus, the controller effectively becomes the <em>adapter</em> between presentation and application concerns as it adapts the JSON DTO to a representation prescribed by the application service.</p><h2>Naming Ports</h2><p>In the diagram, we should treat <em>1 edge of the hexagon as 1 port</em>, and each port is <em>for doing something</em>. So we should always ask ourselves: <em>what is this port for</em>?</p><p>I prefer to name port interfaces according to the action that they perform. Thus, a possible name could be &#8220;ForReservingParkingSpots&#8221;. Alternatively, &#8220;ReserveParkingSpot&#8221; would also serve the purpose of illustrating such an action.</p><p>I would avoid naming these segregated interfaces with only 1 method signature with a noun, because only their implementations typically represent objects that are nouns, as they often implement multiple different port interfaces or represent a real-world concept like ReserveParkingSpotUseCase.</p><h2>Interface Segregation on the Repository Side?</h2><p>If we move our attention again to the driven side of the hexagon, we can see that this naming rule is actually not applied yet. We use &#8220;repository&#8221; in the name for both ports. </p><p>From a ports and adapters perspective, we can also split these two repository interfaces into single ports that only contain one public method signature each. </p><p>This approach can have several advantages, e.g.</p><ol><li><p>Each port can have another implementation, e.g. if queries and commands use different endpoints.</p></li><li><p>Multiple ports can be implemented by one repository, but the application service / hexagon only needs to know about the methods it actually requires.</p></li><li><p>Using stubs and fakes in unit tests is simplified, making it easier to apply <a href="https://www.codecademy.com/article/tdd-outside-in">Outside-In Test-Driven Development</a> where we focus on the interfaces the application interacts with instead of their implementation.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I26T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I26T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 424w, https://substackcdn.com/image/fetch/$s_!I26T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 848w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1272w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I26T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png" width="1456" height="948" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:948,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1183572,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I26T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 424w, https://substackcdn.com/image/fetch/$s_!I26T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 848w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.png 1272w, https://substackcdn.com/image/fetch/$s_!I26T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F787f143c-7405-4301-ae08-3f51d7880d22_2784x1812.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>In practice, it is usually rather inconvenient to separate CRUD repository interfaces into several single-method ports as the user of these interfaces often expects to find these methods in the same place according to the repository pattern. </p><p>This is why I would only split them up if there is a reason for it. On the other hand, if we use a modern IDE, <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">extracting or inlining an interface is trivial</a>, so we can also play around with different designs and decide on a case-by-case basis.</p><p>To name these ports we can ask again &#8220;<em>what is this port for?</em>&#8221;. Reasonable names could be &#8220;ForCheckingActiveReservations&#8221;, &#8220;ForStoringReservations&#8221;, or &#8220;ForFindingParkingSpots&#8221;, or simply their action names &#8220;CheckActiveReservations&#8221;, &#8220;StoreReservation&#8221;, &#8220;FindParkingSpots&#8221;. </p><p>Thinking about ports that way without considering how they are implemented eventually lets us focus much more on what needs to be accomplished by the application from a business perspective rather than how we store the data, a key consideration also when we want to add additional concepts on top of hexagonal architecture, like <a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html">Clean Architecture</a> or <a href="https://thedomaindrivendesign.io/what-is-tactical-design/">Domain-Driven Design Tactical Patterns</a>.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;519d1670-17f3-42f2-a54d-64c86f51118c&quot;,&quot;duration&quot;:null}"></div><h2>Ports Location</h2><p>As a reminder, both inbound and outbound ports are defined in the application / service concern. However, they are used (inbound ports) or implemented (outbound ports) by the respective presentation- or data-access concern class, which are located outside the application concern.</p><h2>Conclusion</h2><p>Interface segregation, one of the 5 SOLID principles, can help us focus an application on the actions it needs to perform, meaning its behaviours, rather than the technologies and patterns used to perform these actions.</p><p>It achieves this by ensuring ports only contain one (or a few) method signature(s) with a specific, actionable name each like &#8220;ForStoringReservations&#8221; or &#8220;StoreReservation&#8221; instead of generic noun-based names that are magnets for all kind of unrelated method calls. </p><p>However, keep in mind that having a large number of one-method interfaces can be cumbersome to work with as well, so combining related interfaces into one (because they <a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html">change for only one reason</a> and together), e.g. for the sake of creating CRUD repository interfaces, can greatly enhance usability. Balance is key. There is no one size fits all, which is why you should <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">be proficient in your IDE&#8217;s refactoring tools</a>.</p><p>In the <a href="https://codeartify.substack.com/p/adding-domain-driven-design-to-ports">next article</a>, I will have a look at how we can improve expressiveness by introducing concepts from Domain-Driven Design, so if you haven&#8217;t already, subscribe if you don&#8217;t want to miss it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p>]]></content:encoded></item><item><title><![CDATA[Towards Hexagonal Architecture - Dependency Inversion between Business- and Data-Access Concerns]]></title><description><![CDATA[To entirely remove any direct call from the business to the data-access concern, we need to introduce application-specific interfaces that are implemented by the data-access adapters, aka Ports.]]></description><link>https://codeartify.substack.com/p/dependency-inversion</link><guid isPermaLink="false">https://codeartify.substack.com/p/dependency-inversion</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 20 Jan 2025 07:02:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7d438301-6dc3-4a1f-b725-76d92976c59d_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a href="https://codeartify.substack.com/p/separating-data-access-concerns">last article</a>, I showed how to separate data access from business concerns in a <a href="https://github.com/codeartify/examples/blob/separating-data-access-concerns/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">codebase</a> by creating an adapter with method signatures that only contain either primitive- or application-specific data types. </p><p>By doing so, I could effectively get rid of the framework-dependent data-access types and repositories, effectively separating the two concerns.</p><h2>Current Dependencies</h2><p>The current application service still depends on the new data-access adapter, as can be seen below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Fkmq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Fkmq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 424w, https://substackcdn.com/image/fetch/$s_!Fkmq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 848w, https://substackcdn.com/image/fetch/$s_!Fkmq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 1272w, https://substackcdn.com/image/fetch/$s_!Fkmq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Fkmq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png" width="1456" height="1243" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1243,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:419670,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Fkmq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 424w, https://substackcdn.com/image/fetch/$s_!Fkmq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 848w, https://substackcdn.com/image/fetch/$s_!Fkmq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 1272w, https://substackcdn.com/image/fetch/$s_!Fkmq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F414c66d2-6d66-4acc-86de-e6e4d2c33c65_1614x1378.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">ParkingSpotReservationService, an application/business service, still depends on the data-access concern by directly referencing ParkingReservation- and ParkingSpotRepositoryAdapter.</figcaption></figure></div><p>I want to visualise this with the following diagram. The data-access adapters effectively separate business concerns from data-access concerns by mapping between the two. Most of the passed data is currently primitive. ParkingSpot is a data structure defined within the <em>application</em> concern and is used by the <em>data-access </em>adapters. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wKh8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wKh8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 424w, https://substackcdn.com/image/fetch/$s_!wKh8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 848w, https://substackcdn.com/image/fetch/$s_!wKh8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 1272w, https://substackcdn.com/image/fetch/$s_!wKh8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wKh8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png" width="1609" height="1299" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/afd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1299,&quot;width&quot;:1609,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:556796,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wKh8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 424w, https://substackcdn.com/image/fetch/$s_!wKh8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 848w, https://substackcdn.com/image/fetch/$s_!wKh8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 1272w, https://substackcdn.com/image/fetch/$s_!wKh8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd3ff89-22c4-42bf-b9d2-bd3b9c776508_1609x1299.png 1456w" sizes="100vw"></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><figcaption class="image-caption">Direct dependencies from application service to data-access repository adapters.</figcaption></figure></div><p>This is actually the first step to invert the dependencies: for a truly business-centric architectural design, the data-access concern needs to depend on the business concern, not the other way round. </p><p>By employing primitive- or application-specific types in the repository adapter&#8217;s method signatures, I already have achieved half of the transformation. </p><p>However, the application service ParkingSpotReservationService still directly calls the data-access repository adapters.</p><h2>Data-Access Adapters inside the Business Concern?</h2><p>To achieve a pure business-centric architecture, both <code>ParkingSpot</code>- and <code>ParkingReservationRepositoryAdapters</code> should not directly be called by the application service anymore.</p><p>This is where Hexagonal Architecture&#8217;s <em>Ports</em> come in handy: we can define interfaces inside the service package / business concern, which are then implemented by these data-access adapters. </p><p>These interfaces are going to be the <em>ports</em> through which the business concern is interfacing and interacting with the data-access concern. </p><p>So let&#8217;s do exactly that by pulling up the method signatures of the two adapters into two interfaces <code>ParkingSpotRepository</code> and <code>ParkingReservationRepository</code>, which are then implemented by the respective adapters:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;9a55dfe5-3521-4313-99cb-5d677f84437e&quot;,&quot;duration&quot;:null}"></div><p>I use IntelliJ&#8217;s built-in features to extract a new interface and place it in the service package (for now. I will show possible package structures in a later article).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xQ1l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xQ1l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 424w, https://substackcdn.com/image/fetch/$s_!xQ1l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 848w, https://substackcdn.com/image/fetch/$s_!xQ1l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 1272w, https://substackcdn.com/image/fetch/$s_!xQ1l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xQ1l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png" width="1380" height="974" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:974,&quot;width&quot;:1380,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:241109,&quot;alt&quot;:&quot;&quot;,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!xQ1l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 424w, https://substackcdn.com/image/fetch/$s_!xQ1l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 848w, https://substackcdn.com/image/fetch/$s_!xQ1l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.png 1272w, https://substackcdn.com/image/fetch/$s_!xQ1l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd3ba10-0a1f-46b3-a4c2-6d008b00577f_1380x974.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><figcaption class="image-caption">Creating a new port (interface) for the ParkingReservationRepository within the service package (business concern).</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RLtL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RLtL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 424w, https://substackcdn.com/image/fetch/$s_!RLtL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 848w, https://substackcdn.com/image/fetch/$s_!RLtL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 1272w, https://substackcdn.com/image/fetch/$s_!RLtL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RLtL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png" width="1456" height="277" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:277,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80420,&quot;alt&quot;:&quot;&quot;,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!RLtL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 424w, https://substackcdn.com/image/fetch/$s_!RLtL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 848w, https://substackcdn.com/image/fetch/$s_!RLtL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 1272w, https://substackcdn.com/image/fetch/$s_!RLtL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1295eb1-6f4e-41af-9f71-b99943ba308e_1882x358.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The new interface which acts as a port for the business concern to interact with the data-access concern.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!b2OE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!b2OE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 424w, https://substackcdn.com/image/fetch/$s_!b2OE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 848w, https://substackcdn.com/image/fetch/$s_!b2OE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 1272w, https://substackcdn.com/image/fetch/$s_!b2OE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!b2OE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png" width="1456" height="955" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:955,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:292339,&quot;alt&quot;:&quot;&quot;,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!b2OE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 424w, https://substackcdn.com/image/fetch/$s_!b2OE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 848w, https://substackcdn.com/image/fetch/$s_!b2OE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.png 1272w, https://substackcdn.com/image/fetch/$s_!b2OE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c86aab4-ef4d-4688-896e-572a9eeb7042_2006x1316.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><figcaption class="image-caption">The data-access adapter implements the port interface defined in the business concern, effectively inverting the dependency between the two concerns.</figcaption></figure></div><p>You can find the solution on the following branch: <a href="https://github.com/codeartify/examples/blob/introducing-data-access-interfaces/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">introducing-data-access-interfaces</a>.</p><h2>Dependencies after Ports Creation</h2><p>After creating adapters that map between data-access- and business concern, introducing port interfaces as part of the business concern that only use either primitive- or business-concern-specific data types, and making the data-access adapters implement those interfaces, there are finally <em>no</em> direct calls/dependencies from the business- to the data-access concern anymore. </p><p>This can also be seen in the imports declaration at the top of the service: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!frxK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!frxK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 424w, https://substackcdn.com/image/fetch/$s_!frxK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 848w, https://substackcdn.com/image/fetch/$s_!frxK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 1272w, https://substackcdn.com/image/fetch/$s_!frxK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!frxK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png" width="893" height="884" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:884,&quot;width&quot;:893,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:185272,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!frxK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 424w, https://substackcdn.com/image/fetch/$s_!frxK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 848w, https://substackcdn.com/image/fetch/$s_!frxK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.png 1272w, https://substackcdn.com/image/fetch/$s_!frxK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea1946be-1b64-4e52-8a76-d246680b11fc_893x884.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><figcaption class="image-caption">The application service only uses classes and interfaces defined in the service package. There is no dependency on any data-access class or type anymore.</figcaption></figure></div><p>The data-access concern is isolated as well, only depending on the port interface definitions of the application-service package. </p><p>This step finalises the dependency inversion, such that the business- does not depend on the data-access concern anymore, but the other way round.</p><p>It additionally illustrates the dependency relationships between ports and adapters on the driven (right) side of the diagonal line in the hexagon, as the following diagram illustrates:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GoiX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GoiX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 424w, https://substackcdn.com/image/fetch/$s_!GoiX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 848w, https://substackcdn.com/image/fetch/$s_!GoiX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 1272w, https://substackcdn.com/image/fetch/$s_!GoiX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GoiX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png" width="1053" height="815" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:815,&quot;width&quot;:1053,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:185923,&quot;alt&quot;:&quot;&quot;,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!GoiX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 424w, https://substackcdn.com/image/fetch/$s_!GoiX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 848w, https://substackcdn.com/image/fetch/$s_!GoiX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.png 1272w, https://substackcdn.com/image/fetch/$s_!GoiX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd39922c6-060d-4e6f-969c-1bce610761a5_1053x815.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><figcaption class="image-caption">Introducing two application-specific interfaces (ports) ParkingSpot- and ParkingReservationRepository that are implemented by the respective adapters achieve a true business-centric design without dependencies from business- to data-access concern anymore.</figcaption></figure></div><h2>Conclusion</h2><p>Inverting dependencies between business- and data-access concerns is one of the most important steps to move towards a business-centric structure like Hexagonal Architecture. </p><p>The important part to remember is that the interfaces (or <em>ports</em>), together with the data structures they employ in their signatures, are defined within the application concern and implemented by the data-access concern. There can&#8217;t be any dependency from application- to data-access concerns!</p><p>In the <a href="https://codeartify.substack.com/p/interface-segregation">next article</a>, I will show what may still be missing until we can truly speak of Hexagonal Architecture, so subscribe if you haven&#8217;t already not to miss it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p>]]></content:encoded></item><item><title><![CDATA[Towards Hexagonal Architecture - Separating Data-Access- and Business Concerns]]></title><description><![CDATA[Depending on database entity classes in business logic can lead to a big ball of mud over time. Here I will show how to do a clean separation between the two.]]></description><link>https://codeartify.substack.com/p/separating-data-access-concerns</link><guid isPermaLink="false">https://codeartify.substack.com/p/separating-data-access-concerns</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 13 Jan 2025 07:02:26 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a2ddfa88-1fca-4ac1-beda-90e625d5bca7_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a href="https://codeartify.substack.com/p/separating-presentation-concerns">last article</a>, I showed how to separate presentation from business concerns in a <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">codebase</a>. The next step to move towards a business-centric architectural design pattern like Hexagonal Architecture is to separate data-access-concern data structures from business concerns, which I will show here.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c-aF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c-aF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 424w, https://substackcdn.com/image/fetch/$s_!c-aF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 848w, https://substackcdn.com/image/fetch/$s_!c-aF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 1272w, https://substackcdn.com/image/fetch/$s_!c-aF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c-aF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png" width="1456" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:541307,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!c-aF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 424w, https://substackcdn.com/image/fetch/$s_!c-aF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 848w, https://substackcdn.com/image/fetch/$s_!c-aF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 1272w, https://substackcdn.com/image/fetch/$s_!c-aF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F130bcfea-fb2d-4bce-8e85-c569313c8c3f_2690x1486.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">Effectively separating data-access from business concerns requires replacing data-access data structures with business-concern-specific data structures instead.</figcaption></figure></div><p>I will continue with the same codebase on the branch <a href="https://github.com/codeartify/examples/blob/separating-presentation-concerns/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">separating-presentation-concerns</a>. You can also find all the step-by-step modifications in the video below. If you don&#8217;t want to miss future articles on this topic, simply subscribe here:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;78f2cda6-9517-4ee4-bcae-8cb869f011e1&quot;,&quot;duration&quot;:null}"></div><h2>Choosing Appropriate Names for DB Entities</h2><p>Let&#8217;s start by investigating the two entities present in the model package, <code>ParkingReservation</code> and <code>ParkingSpot</code>. Both are actually SQL table rows represented as Java objects: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!veeV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!veeV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 424w, https://substackcdn.com/image/fetch/$s_!veeV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 848w, https://substackcdn.com/image/fetch/$s_!veeV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 1272w, https://substackcdn.com/image/fetch/$s_!veeV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!veeV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png" width="1456" height="416" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:416,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1129496,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!veeV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 424w, https://substackcdn.com/image/fetch/$s_!veeV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 848w, https://substackcdn.com/image/fetch/$s_!veeV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 1272w, https://substackcdn.com/image/fetch/$s_!veeV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1116fa42-7db0-4bb8-999d-d22c72af091c_3741x1069.png 1456w" sizes="100vw"></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><figcaption class="image-caption">ParkingSpot is a data-access class representing 1 row in a SQL table. be an anaemic data class without business rules and only be used to access and store data.</figcaption></figure></div><p>They are part of the data-access framework we use and should not be part of the application service. Neither should they contain any business rules. </p><p>Instead, they should be seen as simple <em>anaemic data containers</em> with respective getters and setters that represent the cells in a SQL row.</p><p>Thus, to better mark these entities as the SQL rows they actually represent, I choose to rename them to:</p><ul><li><p><code>ParkingReservationDBEntity</code> </p></li><li><p><code>ParkingSpotDBEntity</code>.</p></li></ul><p>This will make it easier to distinguish them from application-specific data structures we&#8217;ll introduce later. Additionally, I rename the corresponding repositories accordingly to: </p><ul><li><p><code>ParkingReservationDBEntityRepository</code></p></li><li><p><code>ParkingSpotDBEntityRepository</code>.</p></li></ul><h2>Mapping between Business- and Data-Access Concerns</h2><p>An important idea to achieve concern separation and thus independence from the data-access frameworks or technologies is to keep as much of their annotations and magic out of the business concern as possible.</p><p>This means that we need to map between data-access- and business concern data structures that we exchange between these two layers, and that the data-access-to-business-concern mapping function called by the business concern cannot expose any data-access data structure to that business concern.</p><p>So let&#8217;s get started :) </p><h3>Adapting Parking Reservations</h3><p>As a first step, I create a ParkingReservationRepositoryAdapter in a new data_access package and add the ParkingReservationDBEntityRepository as a field. This is going to be the class that handles mapping between data-access and business concerns.</p><p>As a second step, I investigate the application service to see which calls I need to map data to and from. </p><p>The first access to ParkingReservationDBEntityRepository is actually the &#8220;hasActiveReservation&#8221; call. The signature of this method does not have any data-access specific entities, so in theory, it corresponds to the rule that there should be no data-access class in the business service. </p><p>However, I want to eventually get rid of any data-access repository, so I will for now simply let the ParkingReservationRepositoryAdapter delegate this method call to the ParkingReservationDBEntityRepository:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z52m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z52m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 424w, https://substackcdn.com/image/fetch/$s_!Z52m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 848w, https://substackcdn.com/image/fetch/$s_!Z52m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 1272w, https://substackcdn.com/image/fetch/$s_!Z52m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z52m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png" width="1456" height="350" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:350,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99710,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Z52m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 424w, https://substackcdn.com/image/fetch/$s_!Z52m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 848w, https://substackcdn.com/image/fetch/$s_!Z52m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 1272w, https://substackcdn.com/image/fetch/$s_!Z52m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce4943e-f8bc-4964-b9cd-31e7fc36c68e_1546x372.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">New repository adapter that delegates to the ParkingReservationDBEntityRepository.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5c-N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5c-N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 424w, https://substackcdn.com/image/fetch/$s_!5c-N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 848w, https://substackcdn.com/image/fetch/$s_!5c-N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 1272w, https://substackcdn.com/image/fetch/$s_!5c-N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5c-N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png" width="1456" height="803" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:803,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:309508,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5c-N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 424w, https://substackcdn.com/image/fetch/$s_!5c-N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 848w, https://substackcdn.com/image/fetch/$s_!5c-N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.png 1272w, https://substackcdn.com/image/fetch/$s_!5c-N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32ba3b11-fd54-49bb-afe1-c1cd11a02a10_1726x952.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><figcaption class="image-caption">Using the new adapter in the application service. </figcaption></figure></div><h2>Adapting Parking Spots</h2><p>As a next step, I want to create a similar delegation for the ParkingSpotDBEntityRepository&#8217;s findAnyAvailableSpot method. This time, I need to map the DBEntity to a corresponding class of the application service. </p><p>Let&#8217;s implement it as ParkingSpot and add it to the service package. This class will currently only contain the Long id that it gets from the ParkingSpotDBEntity.</p><p>I create a method inside the application service that returns an Optional&lt;ParkingSpot&gt; and map the found ParkingSpotDBEntity&#8217;s id to it if it is not null, effectively getting rid of the implicit null check for availability in the application service. I can then move the method to the ParkingSpotRepositoryAdapter and use it in the application service:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AGO5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AGO5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 424w, https://substackcdn.com/image/fetch/$s_!AGO5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 848w, https://substackcdn.com/image/fetch/$s_!AGO5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 1272w, https://substackcdn.com/image/fetch/$s_!AGO5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AGO5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png" width="888" height="160" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:160,&quot;width&quot;:888,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:27893,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AGO5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 424w, https://substackcdn.com/image/fetch/$s_!AGO5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 848w, https://substackcdn.com/image/fetch/$s_!AGO5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 1272w, https://substackcdn.com/image/fetch/$s_!AGO5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bc320a2-0027-4165-b58b-26d8c3271039_888x160.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The new ParkingSpot record that is part of the business concern (service package). Currently, there is no need for an &#8220;isAvailable&#8221; flag as this is only part of the data-access concern and will be moved later.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8s4f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8s4f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 424w, https://substackcdn.com/image/fetch/$s_!8s4f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 848w, https://substackcdn.com/image/fetch/$s_!8s4f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 1272w, https://substackcdn.com/image/fetch/$s_!8s4f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8s4f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png" width="1256" height="552" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:552,&quot;width&quot;:1256,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113999,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8s4f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 424w, https://substackcdn.com/image/fetch/$s_!8s4f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 848w, https://substackcdn.com/image/fetch/$s_!8s4f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.png 1272w, https://substackcdn.com/image/fetch/$s_!8s4f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa875efa8-e27f-4349-9ddd-a074bfede527_1256x552.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><figcaption class="image-caption">Mapping the found ParkingSpotDBEntity to a business-concern Optional&lt;ParkingSpot&gt;.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9xiF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9xiF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 424w, https://substackcdn.com/image/fetch/$s_!9xiF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 848w, https://substackcdn.com/image/fetch/$s_!9xiF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 1272w, https://substackcdn.com/image/fetch/$s_!9xiF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9xiF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png" width="1456" height="323" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:323,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:103410,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9xiF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 424w, https://substackcdn.com/image/fetch/$s_!9xiF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 848w, https://substackcdn.com/image/fetch/$s_!9xiF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 1272w, https://substackcdn.com/image/fetch/$s_!9xiF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44012fcf-7420-443c-b99a-ed8bf1690525_1910x424.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Using the new findAnyAvailableParkingSpot method in the application service. No ParkingSpotDBEntity present anymore!</figcaption></figure></div><h3>Storing a new Parking Reservation</h3><p>As a third step to remove the framework-dependent data-access repositories, I want to hide to steps to create a new Parking Reservation, i.e. that also a <code>ParkingSpotDBEntity</code>&#8217;s <code>isAvailable</code> field needs to be set to false.</p><p>To do so, I wrap the entire creation &amp; storage of the reservation, together with altering the spot&#8217;s availability, in an own method storeReservation:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c8sK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c8sK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 424w, https://substackcdn.com/image/fetch/$s_!c8sK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 848w, https://substackcdn.com/image/fetch/$s_!c8sK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 1272w, https://substackcdn.com/image/fetch/$s_!c8sK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c8sK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png" width="1456" height="605" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:605,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:151940,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c8sK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 424w, https://substackcdn.com/image/fetch/$s_!c8sK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 848w, https://substackcdn.com/image/fetch/$s_!c8sK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.png 1272w, https://substackcdn.com/image/fetch/$s_!c8sK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2051b28e-5770-4c93-96a7-e08806fa2274_1646x684.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><figcaption class="image-caption">By wrapping the entirety of how the data is stored, a new method storeReservation that only takes primitive types or business-concern types is introduced, effectively mapping again between business- and data-access concerns and not exposing any data-access types in its method signature.</figcaption></figure></div><p>There is one additional step compared to the previous entangled solution to effectively separate the two concerns: I need to find the ParkingSpotDBEntity once again by id and set its availability to false. </p><p>An alternative solution could have wrapped also the search for an available spot, but in my opinion, we would move too much business-relevant logic into the repository adapter. </p><p>I want to keep my repository adapter as dumb as possible for now, and fetching the same parking spot twice seems like a reasonable trade-off. However, this initial solution may change in a later article.</p><p>If we look at the signature, we see that there are only primitives and the ParkingSpot class present. Even though not optimal, this signature is entirely free of data-access-specific classes, so the separation of business- and data-access concerns is almost complete. </p><p>I can finally move the method into the ParkingReservationRepositoryAdapter:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Gzse!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Gzse!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 424w, https://substackcdn.com/image/fetch/$s_!Gzse!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 848w, https://substackcdn.com/image/fetch/$s_!Gzse!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 1272w, https://substackcdn.com/image/fetch/$s_!Gzse!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Gzse!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png" width="1456" height="749" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:749,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:225995,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Gzse!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 424w, https://substackcdn.com/image/fetch/$s_!Gzse!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 848w, https://substackcdn.com/image/fetch/$s_!Gzse!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.png 1272w, https://substackcdn.com/image/fetch/$s_!Gzse!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a0c2670-630a-4d52-a4a7-2c46872ff991_1994x1026.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>And use it in the application service:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6pqJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6pqJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 424w, https://substackcdn.com/image/fetch/$s_!6pqJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 848w, https://substackcdn.com/image/fetch/$s_!6pqJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 1272w, https://substackcdn.com/image/fetch/$s_!6pqJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6pqJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png" width="1456" height="1243" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1243,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:419670,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6pqJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 424w, https://substackcdn.com/image/fetch/$s_!6pqJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 848w, https://substackcdn.com/image/fetch/$s_!6pqJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.png 1272w, https://substackcdn.com/image/fetch/$s_!6pqJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cc25f43-d8fa-4691-a252-1176eb74a31b_1614x1378.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><figcaption class="image-caption">Using only adapters for repositories and effectively hiding away the data-access types, repositories, and frameworks used to store and retrieve parking spots and - reservations.</figcaption></figure></div><p>This solution now contains no data-access types like ParkingSpotDBEntity or ParkingReservationDBEntity anymore but only business-concern-specific ParkingSpot and primitive data types, effectively separating business- from data-access concern. You can find this solution on the <a href="https://github.com/codeartify/examples/blob/separating-data-access-concerns/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">separating-data-access-concerns</a> branch.</p><h2>Conclusion</h2><p>In this article, I have demonstrated how we can separate the business- and data-access concerns by introducing adapters that map between the two. </p><p>There is still some work left: even though the methods of the adapter classes already only use application-specific data structures or primitive types, the application service still depends on these adapters, which means that the business concern knows about the data-access concern. </p><p><a href="https://codeartify.substack.com/p/dependency-inversion">In a next step</a>, therefore, I want to demonstrate how to finally get rid of any data-access dependency and implement a truly business-centric architectural design pattern reminiscent of Hexagonal Architecture. Subscribe if you don&#8217;t want to miss it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This article is part of a series moving towards a business-centric architectural design. See the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a> to get started.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p><p></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">CodeArtify Blog is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Towards Hexagonal Architecture - Separating Presentation Concerns]]></title><description><![CDATA[In this article, I show how we can refactor code such that the presentation concern is untangled from the business concern, an important step towards Hexagonal Architecture.]]></description><link>https://codeartify.substack.com/p/separating-presentation-concerns</link><guid isPermaLink="false">https://codeartify.substack.com/p/separating-presentation-concerns</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 06 Jan 2025 07:02:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/842474ea-f6bd-4007-a945-89752510df26_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In a previous <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">article</a>, I illustrated how to identify different concerns in a <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">codebase</a>. Here I will demonstrate how to separate the presentation concern effectively from this (small) <a href="https://thedomaindrivendesign.io/big-ball-of-mud/">Ball of Mud</a> using the refactoring techniques presented in the following <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">post</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!i7f2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!i7f2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 424w, https://substackcdn.com/image/fetch/$s_!i7f2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 848w, https://substackcdn.com/image/fetch/$s_!i7f2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 1272w, https://substackcdn.com/image/fetch/$s_!i7f2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!i7f2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png" width="1456" height="808" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:808,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:546580,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!i7f2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 424w, https://substackcdn.com/image/fetch/$s_!i7f2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 848w, https://substackcdn.com/image/fetch/$s_!i7f2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 1272w, https://substackcdn.com/image/fetch/$s_!i7f2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faad5f92c-c46f-41b5-9dd5-3fd7918192aa_2684x1490.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">We will separate presentation- from business concerns in this article.</figcaption></figure></div><h2>Presentation Concern And Application Services</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PMQm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PMQm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 424w, https://substackcdn.com/image/fetch/$s_!PMQm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 848w, https://substackcdn.com/image/fetch/$s_!PMQm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!PMQm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PMQm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png" width="2131" height="1125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1125,&quot;width&quot;:2131,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:621481,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!PMQm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 424w, https://substackcdn.com/image/fetch/$s_!PMQm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 848w, https://substackcdn.com/image/fetch/$s_!PMQm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!PMQm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa798307b-8bc9-4e99-a725-f3998b046246_2131x1125.png 1456w" sizes="100vw"></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>The presentation concern has three major tasks:</p><ol><li><p>Mapping incoming presentation data (e.g. a JSON) to an application-service-specific input format.</p></li><li><p>Invoking the application service&#8217;s use case method.</p></li><li><p>Mapping any potential output from the application service to a presentation output format (e.g. HTTP / JSON).</p></li></ol><p>It&#8217;s not necessarily the presentation concern&#8217;s task to validate input data. Instead, the service method needs to ensure that only valid data can be used to invoke it and handle cases of invalid data. This could be throwing exceptions or returning an error result.</p><p>Let&#8217;s get back to the codebase you can find <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">here</a> and move all presentation concerns out of the service and into the controller!</p><h2>Separating Presentation Concerns from Application Service</h2><p>There are several places in reserveParkingSpot where presentation data structures are directly accessed and presentation logic is used to create and return presentation-specific results, see the orange parts below. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SGEy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SGEy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 424w, https://substackcdn.com/image/fetch/$s_!SGEy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 848w, https://substackcdn.com/image/fetch/$s_!SGEy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 1272w, https://substackcdn.com/image/fetch/$s_!SGEy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SGEy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png" width="1456" height="1293" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1293,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1301994,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SGEy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 424w, https://substackcdn.com/image/fetch/$s_!SGEy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 848w, https://substackcdn.com/image/fetch/$s_!SGEy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.png 1272w, https://substackcdn.com/image/fetch/$s_!SGEy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0916645f-8e8a-4006-a206-5612e815f9de_2078x1846.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><figcaption class="image-caption">The entire application-service use-case method with different concerns.</figcaption></figure></div><p>However, converting input and results to and from the application service should only happen in the presentation concern, meaning in the corresponding <code>ParkingSpotReservationController</code>, which currently only delegates inputs to the service method without any mapping and directly returns whatever the service produces:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zGCn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zGCn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 424w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 848w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1272w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zGCn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png" width="1456" height="338" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:338,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zGCn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 424w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 848w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1272w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">ParkingSpotReservationController does not handle presentation logic (mapping to and from the application-service method) but simply delegates presentation data structures to the application service.</figcaption></figure></div><p>Let&#8217;s get started with the separation! You can also watch the following video alongside to see the <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">applied refactoring techniques</a> in action.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;41903460-6d8d-47e0-9205-8f0a2dc99d8c&quot;,&quot;duration&quot;:null}"></div><p></p><h3>Isolate Presentation DTOs</h3><p>Currently, there are multiple accesses to the request&#8217;s startTime, endTime, and reservedBy fields. To access them independently from the presentation&#8217;s <code>ParkingReservationRequest</code> DTO, we can first extract the 3 fields into separate local variables and use them instead of the request&#8217;s getters:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zCWD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zCWD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 424w, https://substackcdn.com/image/fetch/$s_!zCWD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 848w, https://substackcdn.com/image/fetch/$s_!zCWD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 1272w, https://substackcdn.com/image/fetch/$s_!zCWD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zCWD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png" width="2224" height="689" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:689,&quot;width&quot;:2224,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:223577,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zCWD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 424w, https://substackcdn.com/image/fetch/$s_!zCWD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 848w, https://substackcdn.com/image/fetch/$s_!zCWD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.png 1272w, https://substackcdn.com/image/fetch/$s_!zCWD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd10c9266-6f96-4185-9d35-6753aae3bd61_2224x689.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>We can apply the same to the reservation&#8217;s ID at the end of the method when we map back to a <code>ParkingReservationResponse</code> DTO:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VxW0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VxW0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 424w, https://substackcdn.com/image/fetch/$s_!VxW0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 848w, https://substackcdn.com/image/fetch/$s_!VxW0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 1272w, https://substackcdn.com/image/fetch/$s_!VxW0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VxW0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png" width="1446" height="572" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:572,&quot;width&quot;:1446,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128367,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VxW0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 424w, https://substackcdn.com/image/fetch/$s_!VxW0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 848w, https://substackcdn.com/image/fetch/$s_!VxW0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.png 1272w, https://substackcdn.com/image/fetch/$s_!VxW0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36115bc-4268-4834-b6f4-d7b9b3e02fb4_1446x572.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>We already achieved some local separation by only using primitive data types like <code>LocalDateTime</code> or <code>String</code> that are neither presentation-, nor data-access or business-concern-specific. </p><h3>Replace Return Types with Exceptions</h3><p>As a next step, we need to separate HTTP return values from the business rules that cause them. </p><p>To do so, I start to throw business-specific exceptions in the service where the responses were returned previously, and then map them to the HTTP <code>ResponseEntity</code> in the catch clause. </p><p>Let&#8217;s start by adding the try-catch around the non-presentation part of the <code>reserveParkingSpot</code> use case method:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!da0w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!da0w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 424w, https://substackcdn.com/image/fetch/$s_!da0w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 848w, https://substackcdn.com/image/fetch/$s_!da0w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 1272w, https://substackcdn.com/image/fetch/$s_!da0w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!da0w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png" width="1456" height="1292" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1292,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:308494,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!da0w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 424w, https://substackcdn.com/image/fetch/$s_!da0w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 848w, https://substackcdn.com/image/fetch/$s_!da0w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.png 1272w, https://substackcdn.com/image/fetch/$s_!da0w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ddb128c-a24d-457b-8f13-712b23aee996_1842x1634.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>We need to also move the <code>Long reservationId</code> outside of the try-catch as we need to return it from the service and then use it in the <code>ParkingReservationResponse</code>. </p><p>Let&#8217;s turn the first error case for &#8220;Reservation must be at least 30 minutes long.&#8221; into an exception <code>ReservationShorterThan30MinutesException</code> and handle the case in the catch part.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1lhV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1lhV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 424w, https://substackcdn.com/image/fetch/$s_!1lhV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 848w, https://substackcdn.com/image/fetch/$s_!1lhV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 1272w, https://substackcdn.com/image/fetch/$s_!1lhV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1lhV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png" width="1762" height="54" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:54,&quot;width&quot;:1762,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30500,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1lhV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 424w, https://substackcdn.com/image/fetch/$s_!1lhV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 848w, https://substackcdn.com/image/fetch/$s_!1lhV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 1272w, https://substackcdn.com/image/fetch/$s_!1lhV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98172995-5656-47bd-9b26-edcc50f16bf1_1762x54.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S-If!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S-If!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 424w, https://substackcdn.com/image/fetch/$s_!S-If!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 848w, https://substackcdn.com/image/fetch/$s_!S-If!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 1272w, https://substackcdn.com/image/fetch/$s_!S-If!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S-If!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png" width="1860" height="1675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1675,&quot;width&quot;:1860,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:423079,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S-If!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 424w, https://substackcdn.com/image/fetch/$s_!S-If!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 848w, https://substackcdn.com/image/fetch/$s_!S-If!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.png 1272w, https://substackcdn.com/image/fetch/$s_!S-If!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54828cfe-70da-4ccf-9f21-b07526a1c35f_1860x1675.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>We should do this for all the exceptional cases. We can additionally introduce the following exceptions in the service package:</p><ul><li><p><code>EndTimeMustBeAfterStartTimeException</code></p></li><li><p><code>ReservationOutsideOperatingHoursException</code></p></li><li><p><code>ActiveReservationExistsException</code></p></li><li><p><code>NoAvailableSpotsException</code></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_!nrB5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nrB5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 424w, https://substackcdn.com/image/fetch/$s_!nrB5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 848w, https://substackcdn.com/image/fetch/$s_!nrB5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 1272w, https://substackcdn.com/image/fetch/$s_!nrB5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nrB5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png" width="1456" height="1109" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1109,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:331077,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nrB5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 424w, https://substackcdn.com/image/fetch/$s_!nrB5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 848w, https://substackcdn.com/image/fetch/$s_!nrB5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.png 1272w, https://substackcdn.com/image/fetch/$s_!nrB5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F952bca57-a792-418c-b437-081b226e3c4d_2242x1708.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>And handle them accordingly in the catch clause:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1CW5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1CW5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 424w, https://substackcdn.com/image/fetch/$s_!1CW5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 848w, https://substackcdn.com/image/fetch/$s_!1CW5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!1CW5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1CW5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png" width="1456" height="951" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:951,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:349501,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1CW5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 424w, https://substackcdn.com/image/fetch/$s_!1CW5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 848w, https://substackcdn.com/image/fetch/$s_!1CW5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!1CW5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e400f1-38b0-43db-b90b-411aa6b0603e_1838x1200.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>Physically separating business rules further from presentation logic.</p><h3>Move Presentation Concerns to Controller</h3><p>Now we can <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">extract</a> the part within the <code>try {}</code> block into an own method, for example <code>reserveParkingSpot2</code>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ub8d!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ub8d!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 424w, https://substackcdn.com/image/fetch/$s_!ub8d!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 848w, https://substackcdn.com/image/fetch/$s_!ub8d!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 1272w, https://substackcdn.com/image/fetch/$s_!ub8d!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ub8d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png" width="1456" height="550" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:550,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:194965,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ub8d!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 424w, https://substackcdn.com/image/fetch/$s_!ub8d!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 848w, https://substackcdn.com/image/fetch/$s_!ub8d!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.png 1272w, https://substackcdn.com/image/fetch/$s_!ub8d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765d3202-64dc-4f7b-84e5-10764c5713f6_1836x694.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><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!et5-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!et5-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 424w, https://substackcdn.com/image/fetch/$s_!et5-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 848w, https://substackcdn.com/image/fetch/$s_!et5-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 1272w, https://substackcdn.com/image/fetch/$s_!et5-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!et5-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png" width="2300" height="472" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:472,&quot;width&quot;:2300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156290,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!et5-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 424w, https://substackcdn.com/image/fetch/$s_!et5-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 848w, https://substackcdn.com/image/fetch/$s_!et5-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 1272w, https://substackcdn.com/image/fetch/$s_!et5-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a3f2d2-ecea-4a86-804e-82dd1db30836_2300x472.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>We can turn this method public and <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">inline</a> the outer reserveParkingSpot method into the <code>ParkingSpotReservationController</code>, and then <a href="https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials">rename</a> it to <code>reserveParkingSpot</code>. </p><p>The final service method is free of any presentation concern:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4K23!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4K23!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 424w, https://substackcdn.com/image/fetch/$s_!4K23!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 848w, https://substackcdn.com/image/fetch/$s_!4K23!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 1272w, https://substackcdn.com/image/fetch/$s_!4K23!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4K23!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png" width="1430" height="1814" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1814,&quot;width&quot;:1430,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:397849,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4K23!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 424w, https://substackcdn.com/image/fetch/$s_!4K23!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 848w, https://substackcdn.com/image/fetch/$s_!4K23!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.png 1272w, https://substackcdn.com/image/fetch/$s_!4K23!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c684970-4ba5-4608-a18c-ff92758e834b_1430x1814.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>The controller, on the other hand, now does exactly what I initially outlined. It:</p><ol><li><p>Maps incoming presentation data to an application-service-specific input format.</p></li><li><p>Invokes the application service&#8217;s use case method.</p></li><li><p>Maps any potential output from the application service to a presentation output format (e.g. HTTP / JSON).</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M6Ar!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M6Ar!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 424w, https://substackcdn.com/image/fetch/$s_!M6Ar!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 848w, https://substackcdn.com/image/fetch/$s_!M6Ar!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 1272w, https://substackcdn.com/image/fetch/$s_!M6Ar!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M6Ar!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png" width="1456" height="1663" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1663,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:411992,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M6Ar!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 424w, https://substackcdn.com/image/fetch/$s_!M6Ar!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 848w, https://substackcdn.com/image/fetch/$s_!M6Ar!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.png 1272w, https://substackcdn.com/image/fetch/$s_!M6Ar!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c88c3c8-4cf4-45a1-a3c1-bd061e64f098_1476x1686.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>There are still other transformations possible, but for presentation concern separation, this is about it! You can find this solution on the following branch: <a href="https://github.com/codeartify/examples/blob/separating-presentation-concerns/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">separating-presentation-concerns</a>.</p><h2>Conclusion</h2><p>In this post, I demonstrated how to effectively remove presentation concerns from application service by introducing service-specific exceptions and handling them within a try-catch block. </p><p>In the <a href="https://codeartify.substack.com/p/separating-data-access-concerns">next post</a>, I will also encapsulate data access concerns and remove them from the service method, so stay tuned if you don&#8217;t want to miss it by subscribing to our blog:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>If you want to effectively discern concerns, see the following <a href="https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code">post</a>.</p><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>.</p>]]></content:encoded></item><item><title><![CDATA[Towards Hexagonal Architecture - Identifying Concerns in Legacy Code]]></title><description><![CDATA[Any legacy application can be turned into Hexagonal Architecture if we know how to. Understanding and discerning the different concerns in any application is the first step towards that.]]></description><link>https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code</link><guid isPermaLink="false">https://codeartify.substack.com/p/effectively-separating-concerns-in-legacy-code</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 30 Dec 2024 07:00:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/19509819-54f0-41a6-bf0d-1798b1453d44_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Framework-Specific Structure Fallacies</h2><p>Any framework or language has a specific convention of how to structure code. If you work with Java and Spring Boot, the following package structure may look familiar:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hGfC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hGfC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 424w, https://substackcdn.com/image/fetch/$s_!hGfC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 848w, https://substackcdn.com/image/fetch/$s_!hGfC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 1272w, https://substackcdn.com/image/fetch/$s_!hGfC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hGfC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png" width="576" height="438" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:438,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:46847,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hGfC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 424w, https://substackcdn.com/image/fetch/$s_!hGfC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 848w, https://substackcdn.com/image/fetch/$s_!hGfC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 1272w, https://substackcdn.com/image/fetch/$s_!hGfC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff03a3a1e-03f3-47b5-9058-27e2b17c4b74_576x438.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">Typical Spring Boot folder structure, showing controller, service, repository and various additional packages for DTOs, models, etc. </figcaption></figure></div><p>There are many applications that follow exactly this structure and it can feel impossible to move towards a more business-centric architectural design like <a href="https://www.youtube.com/watch?v=k0ykTxw7s0Y">Hexagonal Architecture by Alistair Cockburn</a> without the right approach.</p><p>This is why I will provide a step-by-step guide to achieve exactly that. </p><p>Because the entire topic is pretty large, I split it into a couple of articles that I will publish about once a week. You can follow along using my <a href="https://github.com/codeartify/examples/tree/main/src/main/java/com/codeartify/examples/parking_spot_reservation">repository</a>. Subscribe if you don&#8217;t want to miss it!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>Before we can move towards Hexagonal Architecture, we need to be able to effectively <strong>identify different concerns</strong>. This is what I will look at in this article.</p><h2>Typical Concerns in any Application</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!baGW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!baGW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 424w, https://substackcdn.com/image/fetch/$s_!baGW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 848w, https://substackcdn.com/image/fetch/$s_!baGW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 1272w, https://substackcdn.com/image/fetch/$s_!baGW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!baGW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png" width="1456" height="846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:544418,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!baGW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 424w, https://substackcdn.com/image/fetch/$s_!baGW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 848w, https://substackcdn.com/image/fetch/$s_!baGW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.png 1272w, https://substackcdn.com/image/fetch/$s_!baGW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fd435c0-da6c-49b5-80a8-807f9939a512_2623x1524.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>There are 3 to 4 concerns that any application has, which are:</p><ol><li><p><strong>Data Access</strong>: how we retrieve and store data. These are typically in-memory, file system, databases, or surrounding system calls. </p></li><li><p><strong>Presentation</strong>: how data is presented to a user. This can involve JSON data structures, HTML pages, XML, PDF, or any other data and presentation logic that is used to deliver data from the user to the system and then back again by the system to the user. </p></li><li><p><strong>Application/Business</strong>: the actual core of any software. Also referred to as &#8220;business rules&#8221;, this is how a company makes or saves money. While data access and presentation concerns may change frequently due to framework updates or exchange of technologies, the application concern should actually only change when business processes change. It&#8217;s best kept free of framework-specific code. This is sometimes impractical and there are exceptions to this rule, but the mindset when implementing this concern is to keep external dependencies to a minimum. </p></li></ol><p>I said 3 to 4 concerns, so here&#8217;s the 4th concern which is not necessarily required but helps with emphasising the business view: </p><ol start="4"><li><p><strong>Domain</strong>: we can split off the domain concern from the application concern if we are interested in creating a rich domain model as described by <a href="https://learning.oreilly.com/library/view/learning-domain-driven-design/9781098100124/">Domain-Driven Design</a>. Although not essential, it is highly advisable to create a richer domain model to capture business rules and decisions, especially if we are dealing in complex business domains.</p></li></ol><p>If we split the domain concern off from the application concern, then the application concern is tasked with checking global validation, retrieving and storing domain entities, and invoking a domain entity&#8217;s business rules.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CgI0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CgI0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 424w, https://substackcdn.com/image/fetch/$s_!CgI0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 848w, https://substackcdn.com/image/fetch/$s_!CgI0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 1272w, https://substackcdn.com/image/fetch/$s_!CgI0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CgI0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png" width="4184" height="446" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:446,&quot;width&quot;:4184,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:482169,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CgI0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 424w, https://substackcdn.com/image/fetch/$s_!CgI0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 848w, https://substackcdn.com/image/fetch/$s_!CgI0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 1272w, https://substackcdn.com/image/fetch/$s_!CgI0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7465216f-6b19-4a3a-bc5f-b15d703917ce_4184x446.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Typical tasks of an application service if we use an additional domain model.</figcaption></figure></div><p>In the following, I will mainly focus on the 3 concerns presentation, data access, and application. Domain will become relevant in later articles when I will show how to move towards a more business-centric structure.</p><h2>A Naive Approach to Identifying Concerns</h2><p>After laying out the basic building blocks of an application, let&#8217;s investigate the Spring Boot app again. Where are the 3 concerns located? A naive interpretation could be the following:</p><p><em>The controller package is concerned with presentation logic. The repository package is concerned with data access. The service package contains application-specific service classes. And then we have the DTO package for JSON representations of the presentation concern, and a model package for the domain model. </em></p><p>Makes sense, right? Unfortunately no. </p><p>In reality, Spring Boot mixes up several different concepts from MVC and DDD and probably others as well. For example, let&#8217;s see what the <a href="https://docs.spring.io/spring-framework/docs/6.2.x/javadoc-api/org/springframework/stereotype/Service.html">@Service annotation</a> defines:</p><blockquote><p>public @interface <strong>Service</strong></p><p>Indicates that an annotated class is a "Service", originally defined by Domain-Driven Design (Evans, 2003) as "an operation offered as an interface that stands alone in the model, with no encapsulated state."</p><p>May also indicate that a class is a "Business Service Facade" (in the Core J2EE patterns sense), <em>or something similar</em>. This annotation is a <em>general-purpose stereotype</em> and individual teams may narrow their semantics and use as appropriate.</p></blockquote><p>We see that it can basically be anything a developer team may define as a &#8220;service&#8221;. This is not helpful but on the contrary, a great way to create chaos before even getting started, as everyone has another definition of what a &#8220;service&#8221; entails. </p><p>Conclusively, we cannot rely on framework-defined stereotypes to effectively identify concerns, a point I want to drive home even more with the following analysis.</p><h2>Identifying Real Concerns in Code </h2><p>Let&#8217;s take a look at the following code snippet you can find <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parking_spot_reservation/service/ParkingSpotReservationService.java">here</a>. Can you easily spot what concern this class belongs to?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!b0PJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!b0PJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 424w, https://substackcdn.com/image/fetch/$s_!b0PJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 848w, https://substackcdn.com/image/fetch/$s_!b0PJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 1272w, https://substackcdn.com/image/fetch/$s_!b0PJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!b0PJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png" width="1456" height="1293" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1293,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:603004,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!b0PJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 424w, https://substackcdn.com/image/fetch/$s_!b0PJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 848w, https://substackcdn.com/image/fetch/$s_!b0PJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.png 1272w, https://substackcdn.com/image/fetch/$s_!b0PJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16548c86-f6e1-4e9e-a150-9469b5b33c3b_2078x1846.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>The class name suggests that it is an <em>application-specific service</em>. This means it should concern itself only with coordinating and applying business rules. </p><p>However, let&#8217;s look at the service method&#8217;s signature:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qqo4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qqo4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 424w, https://substackcdn.com/image/fetch/$s_!qqo4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 848w, https://substackcdn.com/image/fetch/$s_!qqo4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 1272w, https://substackcdn.com/image/fetch/$s_!qqo4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qqo4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png" width="1456" height="51" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:51,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38095,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qqo4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 424w, https://substackcdn.com/image/fetch/$s_!qqo4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 848w, https://substackcdn.com/image/fetch/$s_!qqo4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 1272w, https://substackcdn.com/image/fetch/$s_!qqo4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9527a02a-3244-4d05-86cc-63134b785b33_1766x62.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The return type indicates a REST HTTP response, which is part of the presentation concern. The same is true for the <code>ParkingReservationRequest</code>, which is a Java DTO representation for a user-provided data structure, most likely JSON. It is directly passed from the controller to the service, as can be seen here:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zGCn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zGCn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 424w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 848w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1272w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zGCn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png" width="2312" height="536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:536,&quot;width&quot;:2312,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:203931,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zGCn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 424w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 848w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1272w, https://substackcdn.com/image/fetch/$s_!zGCn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73b52b27-e4b0-4843-bd01-d924660fad98_2312x536.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Application-specific services should not use data structures from the presentation concern</em>. </p><p>If we look a bit deeper into the service&#8217;s <code>reserveParkingSpot</code> method, we find three <a href="https://refactoring.guru/replace-nested-conditional-with-guard-clauses">guard clauses</a> that need to be passed before the reservation request is processed any further:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!huPr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!huPr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 424w, https://substackcdn.com/image/fetch/$s_!huPr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 848w, https://substackcdn.com/image/fetch/$s_!huPr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 1272w, https://substackcdn.com/image/fetch/$s_!huPr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!huPr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png" width="1456" height="357" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:357,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:279372,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!huPr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 424w, https://substackcdn.com/image/fetch/$s_!huPr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 848w, https://substackcdn.com/image/fetch/$s_!huPr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 1272w, https://substackcdn.com/image/fetch/$s_!huPr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb648e306-25c3-4ecf-aaf7-f9092c87f1fb_2674x656.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Guard clauses at the beginning of the reserveParkingSpot method.</figcaption></figure></div><p>This is actually a mix of business rules and presentation logic. The business rules are the checks on both start- and end time, which are taken directly from the presentation concern&#8217;s request DTO, and then the code returns a presentation-specific <code>ResponseEntity</code> object with corresponding HTTP status codes. There is an awful lot of presentation logic going on in this business-application-specific service. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4Cp9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4Cp9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 424w, https://substackcdn.com/image/fetch/$s_!4Cp9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 848w, https://substackcdn.com/image/fetch/$s_!4Cp9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 1272w, https://substackcdn.com/image/fetch/$s_!4Cp9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4Cp9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png" width="1456" height="436" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:436,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:270253,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4Cp9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 424w, https://substackcdn.com/image/fetch/$s_!4Cp9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 848w, https://substackcdn.com/image/fetch/$s_!4Cp9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.png 1272w, https://substackcdn.com/image/fetch/$s_!4Cp9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20104092-c4f5-4baf-a1d1-818375205f48_2674x800.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><figcaption class="image-caption">Business rules entangled with presentation DTOs and -logic.</figcaption></figure></div><p>In the next couple of lines, presentation concerns and business rules are additionally entangled in data access concerns:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!If-p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!If-p!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 424w, https://substackcdn.com/image/fetch/$s_!If-p!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 848w, https://substackcdn.com/image/fetch/$s_!If-p!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!If-p!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!If-p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png" width="1456" height="567" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:567,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:506524,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!If-p!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 424w, https://substackcdn.com/image/fetch/$s_!If-p!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 848w, https://substackcdn.com/image/fetch/$s_!If-p!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!If-p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1402150-ccf5-4319-b258-bef0a44065e0_3080x1200.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><figcaption class="image-caption">Entangled business rules within presentation and data-access concerns.</figcaption></figure></div><p><code>ParkingSpot</code> is a database entity, basically an object representation of a database table row in the case of SQL, and not a real business object, even though it is typically stored in the <code>model</code> package.</p><p>Checking if the spot returned from the repository is null is an indirect and highly ambiguous way to represent the business rule that <em>a spot needs to be free to be reservable</em>.</p><p>In the case of making a parking spot reservation, we actually mix both business rules and data access concerns so smoothly together that we cannot simply distinguish the two visually, which is why I use a blue-green gradient to do so. </p><p>Reserving a parking spot means creating a <code>ParkingReservation</code> database entity entry and setting the <code>ParkingSpot&#8217;s</code> availability to <code>false</code>. </p><p>However, this actually only represents how we <em>store</em> the information in the database and obscures the business rule &#8220;reserve parking spot&#8221;. We rely solely on the interpretation- and mental-mapping abilities of a programmer to understand its semantics. This may be acceptable in a simple example like the one presented here, but can quickly turn almost impossible to maintain in a more complex environment.</p><p>If we look closer into the query of the repository methods, we find additional business rules encoded:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D0e7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D0e7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 424w, https://substackcdn.com/image/fetch/$s_!D0e7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 848w, https://substackcdn.com/image/fetch/$s_!D0e7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 1272w, https://substackcdn.com/image/fetch/$s_!D0e7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D0e7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png" width="1456" height="181" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:181,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:104234,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D0e7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 424w, https://substackcdn.com/image/fetch/$s_!D0e7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 848w, https://substackcdn.com/image/fetch/$s_!D0e7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 1272w, https://substackcdn.com/image/fetch/$s_!D0e7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cc60c3-eec4-4a6c-87ba-7cb22390deb3_2150x268.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Business rule &#8220;fetch parking spot randomly&#8221; encoded in a repository query.</figcaption></figure></div><p>Apparently, we get the next <em>randomly</em> available parking spot. We could decide to implement that differently, e.g. if we want to provide different categories of parking spots to customers. It&#8217;s a business decision to <em>randomly </em>select a free spot, so we mix business- with data access concerns once again.</p><p>In a last step, we map the data from the presentation request and the database entity&#8217;s ID to a presentation response DTO. None of this should happen directly within an application service, which should only handle business-application-specific concerns.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3pQ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3pQ6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 424w, https://substackcdn.com/image/fetch/$s_!3pQ6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 848w, https://substackcdn.com/image/fetch/$s_!3pQ6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 1272w, https://substackcdn.com/image/fetch/$s_!3pQ6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3pQ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png" width="1358" height="650" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1358,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:132356,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3pQ6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 424w, https://substackcdn.com/image/fetch/$s_!3pQ6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 848w, https://substackcdn.com/image/fetch/$s_!3pQ6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.png 1272w, https://substackcdn.com/image/fetch/$s_!3pQ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc17619-7487-4c7c-9fa8-d28bcd4de345_1358x650.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><figcaption class="image-caption">Mapping presentation- and data access objects to presentation result DTO directly within the application-service method &#8220;reserveParkingSpot&#8221;, further entangling unrelated concerns.</figcaption></figure></div><h2>Conclusion</h2><p>In this small example, I have demonstrated how framework-specific stereotypes and attributes like @Service are no guarantee at all to identify different concerns effectively.</p><p>On the contrary, because frameworks are typically expected to accommodate as many developer and team interpretations as possible, it&#8217;s easy to unintentionally mix different concerns without even realising it.</p><p>In the case of complex business logic, this mixing of concerns can heavily impact our ability to change software quickly and cheaply over time because the codebase deteriorates into a Big Ball of Mud.</p><p>Being able to quickly discern different concerns within our codebase is a vital skill needed to move towards a more business-centric application structure. In the <a href="https://codeartify.substack.com/p/separating-presentation-concerns">upcoming articles</a>, I will step-by-step illustrate how to transform the presented codebase into a Hexagonal Architecture / Ports and Adapters. </p><p>If you don&#8217;t want to miss it, just subscribe here:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Resources</h2><p>This series of articles is an addition to the <a href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture">From Layered to Hexagonal Architecture in 2 steps article</a>.</p><p>We touch on the same topics in our O&#8217;Reilly course <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">&#8220;DDD, EventStorming, and Clean Architecture&#8221;</a>. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Clean Architecture.</p><p>If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop <a href="https://codeartify.com/en/courses/modern-software-architecture">Modern Software Architecture Design Patterns</a>. </p>]]></content:encoded></item><item><title><![CDATA[1 to Many Without Breakage: One of TDD’s Best-Kept Secrets]]></title><description><![CDATA[TDD can become tricky when the next transformation step from red to green includes replacing a single element with a collection. I demonstrate how Parallel Change can help here as well.]]></description><link>https://codeartify.substack.com/p/1-to-many-without-breakage</link><guid isPermaLink="false">https://codeartify.substack.com/p/1-to-many-without-breakage</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Tue, 10 Dec 2024 07:01:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1c02645f-35b2-4cd5-ae1a-1c721e8711c1_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;04630667-3796-4d91-9c6b-e0be5db198dd&quot;,&quot;duration&quot;:null}"></div><p><a href="https://codeartify.substack.com/p/seamless-code-changes-with-parallel-change">Parallel Change</a> is one of the most powerful <em>refactoring</em> techniques, but it has also another use: seamlessly moving <em>from a single element to a collection</em> of elements. This corresponds to the transformation step <em>scalar &#8594; array</em> in the <a href="https://blog.cleancoder.com/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html">Transformation Priority Premise (TPP)</a>.</p><p>Often when I moved from 1 to many using TDD, I found myself mindlessly ripping out old code and adding new code. Obviously, I often ended up in a state where my code did not compile anymore for quite some time!</p><p>All of a sudden it clicked - it&#8217;s the same problem that I had while refactoring and exchanging an existing abstraction with a another one. So Parallel Change should help me similarly as it does during refactoring, only this time I use it to move from a failing to a passing test.</p><h2>The Example: Popping 2 Elements from a Stack</h2><p>I take the example of a stack (which I borrow from <a href="https://amzn.eu/d/giviKP8">Clean Craftsmanship</a> by Uncle Bob), which shows exactly the case of moving from 1 element to a collection of elements. The relevant failing test (that you can also find <a href="https://github.com/codeartify/examples/blob/main/src/test/java/com/codeartify/examples/parallel_change_for_red_to_green/StackShould.java">here</a>) reads as follows:</p><pre><code>@Test
void pops_elements_in_the_reverse_order_of_how_they_were_pushed() {
    var stack = new Stack();

    stack.push(99);
    stack.push(88);

    <em>assertEquals</em>(88, stack.pop());
    <em>assertEquals</em>(99, stack.pop());
} </code></pre><p>This test currently fails because of the <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parallel_change_for_red_to_green/Stack.java">following code for a stack</a> which only supports storing <em>1 element</em>, so once 88 is pushed into the stack, 99 gets overwritten:</p><pre><code>public class Stack {
    private int size;
    private int element; // only one element

    public boolean isEmpty() {
        return size == 0;
    }

    public void push(int element) {
        this.element = element; // overrides element
        size++;
    }

    public int pop() {
        if (size == 0) {
            throw new EmptyStackPoppedException();
        }
        size--;
        return element;
    }

    public int size() {
        return size;
    }
}</code></pre><h2>Parallel Change Revisited</h2><p>Let&#8217;s see how we can leverage <a href="https://codeartify.substack.com/p/seamless-code-changes-with-parallel-change">Parallel Change</a> to move this test from red to green by replacing the single <code>element</code> with a <code>List</code>. Here&#8217;s a brief summary of Parallel Change:</p><ol><li><p>Add the new <code>List</code> close to the <code>element</code> to replace.</p></li><li><p>For every time a value is assigned to <code>element</code>, add the same value to the <code>List</code>.</p></li><li><p>Switch all reads from <code>element</code> to an equivalent read operation from the <code>List</code>.</p></li><li><p>Remove all places where the <code>element</code> is assigned a value.</p></li><li><p>Remove the <code>element</code> member variable.</p></li></ol><h2>Applying Parallel Change to Get to Green</h2><p>In step 1, we add the <code>List</code> right below the <code>element</code> and run our tests. Only the test from above should still fail.</p><pre><code><code>public class Stack {
    private int size;
    private int element; 
    private List&lt;Integer&gt; elements = new ArrayList&lt;&gt;(); // new
    
// ...</code></code></pre><p>In step 2, we add a value to the <code>List</code> wherever that value is assigned to <code>element</code>. Here, it&#8217;s only once in the <code>push</code> method. Still the same test should fail because only the state in <code>element</code> and the <code>List</code> are now the same, but we don&#8217;t access the list yet.</p><pre><code>public void push(int element) {
    this.element = element;
    this.elements.add(element); // add this here
    size++;
}</code></pre><p>In the 3rd step, we&#8217;ll make the test green by replacing all read accesses to <code>element</code> with a read access to <code>elements</code>. We leverage the <code>List</code>&#8217;s <code>removeLast</code> in the <code>pop</code> method. Finally, the test is green. </p><pre><code>public int pop() {
    if (size == 0) {
        throw new EmptyStackPoppedException();
    }
    size--;
    // previous: return element;
    return elements.removeLast(); // new line
}</code></pre><p>The step before would have shown us if we actually had the same state in both <code>element</code> and the <code>List</code>. We can now step-by-step remove occurrences where <code>element</code> is assigned a value to (while running our test suite after each step):</p><pre><code><code>public void push(int element) {
    // remove this line: this.element = element;
    this.elements.add(element);
    size++;
}</code></code></pre><p>And finally, we are ready to remove <code>element</code> entirely from the stack, resulting in the following solution:</p><pre><code>public class Stack {
    private int size;
    // removed: private int element;
    private List&lt;Integer&gt; elements = new ArrayList&lt;&gt;();

    public boolean isEmpty() {
        return size == 0;
    }

    public void push(int element) {
        this.elements.add(element);
        size++;
    }

    public int pop() {
        if (size == 0) {
            throw new EmptyStackPoppedException();
        }
        size--;
        return elements.removeLast();
    }

    public int size() {
        return size;
    }
}</code></pre><p>This finalises the Parallel Change for the <em>1 to Many</em> Transformation from <code>element</code> to the <code>List</code>, but we&#8217;re not yet done. We used Parallel Change to move from red to green, and now we enter the <em>refactoring</em> stage! And there is something to refactor: we still have the member variable <code>size</code> that can now be removed, also using Parallel Change, so let&#8217;s apply it once again. </p><h2>Parallel Change for Refactoring Revisited</h2><p>We can skip steps 1 and 2 of the Parallel Change algorithm (achieving the same state in old and new structure) as we already solved the introduction of the new abstraction (<code>elements</code>) and setting the same value as <code>size</code> because every time an element is pushed to the list, it&#8217;s size automatically increases. </p><p>So instead, we can directly move to step 3 and replace all the read accesses to <code>size</code> with a read access to <code>elements</code>. Let&#8217;s start with <code>Stack::isEmpty</code>:</p><pre><code>public boolean isEmpty() {
    // replaced: return size == 0;
    return elements.isEmpty();
}</code></pre><p>Then we move to <code>pop</code>. Here we can use the improved <code>Stack::isEmpty</code> method, which should have been used in the first place as it was a case of D.R.Y:</p><pre><code>public int pop() {
    if (isEmpty()) { // use the public Stack::isEmpty method here
        throw new EmptyStackPoppedException();
    }
    size--;
    return elements.removeLast();
}</code></pre><p>And finally, let&#8217;s also adapt <code>Stack::size</code>:</p><pre><code>public int size() {
    // replaced: return size;
    return elements.size();
}</code></pre><p>Now that we have switched all the read accesses to the <code>List</code>, we can move to step 4 and remove all the places where <code>size</code> is assigned a value:</p><pre><code>public void push(int element) {
    this.elements.add(element);
    // remove: size++;
}

public int pop() {
    if (isEmpty()) {
        throw new EmptyStackPoppedException();
    }
    // remove: size--;
    return elements.removeLast();
}</code></pre><p>And finally, in step 5, we remove the <code>size</code> member variable and are left with the following <code>Stack</code>:</p><pre><code>public class Stack {
    // removed: private int size;
    private List&lt;Integer&gt; elements = new ArrayList&lt;&gt;();

    public boolean isEmpty() {
        return elements.isEmpty();
    }

    public void push(int element) {
        this.elements.add(element);
    }

    public int pop() {
        if (isEmpty()) {
            throw new EmptyStackPoppedException();
        }
        return elements.removeLast();
    }

    public int size() {
        return elements.size();
    }
}</code></pre><p>&#8230; and we never broke a sweat. </p><h2>Conclusion</h2><p>This simple example illustrates how Parallel Change can both be used in TDD to solve the 1 to many transformation and seamlessly move from red to green, and also to replace an existing abstraction with another one in the refactoring phase. </p><p>Applied correctly, we never enter a state of non-compiling code and avoid Analysis Paralysis when we run into problems. I highly recommend you try out the example for yourself in the following <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parallel_change_for_red_to_green/Stack.java">repository</a> (the solution can be found <a href="https://github.com/codeartify/examples/blob/solution_parallel_change_for_red_to_green/src/main/java/com/codeartify/examples/parallel_change_for_red_to_green/Stack.java">here</a>). It&#8217;s a great tool to have in your TDD toolbox!</p><p>Have you applied Parallel Change in that manner before? Do you have other systematic strategies to move from 1 to many in TDD? Write them down in the comments so we can learn from one another!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/p/1-to-many-without-breakage/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://codeartify.substack.com/p/1-to-many-without-breakage/comments"><span>Leave a comment</span></a></p><p>If you like content like that, don&#8217;t forget to subscribe to stay up to date!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>In our<strong> <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">O&#8217;Reilly course</a> </strong>we demonstrate a similar move from 1 to many using Parallel Change for extending a Clean Architecture Use Case from 1 Aggregate to a Repository of Aggregates, step-by-step using TDD. Check it out!</p><p>Want your team to learn how to develop evolvable software solutions? Visit our website<strong> <a href="http://www.codeartify.com/">www.codeartify.com</a> </strong>and get in touch with us! We provide worldwide remote and on-site workshops for you and your team!</p><p>And lastly, if you are not yet part of our great community, check out our <strong><a href="https://www.techexcellence.io/">Tech Excellence Meetup</a></strong> and discuss with other likeminded people in Discord!</p>]]></content:encoded></item><item><title><![CDATA[Seamless Code Changes with Parallel Change]]></title><description><![CDATA[No broken builds when changing code anymore. Commit and merge to main at any time. Continue code changes whenever you have time.]]></description><link>https://codeartify.substack.com/p/seamless-code-changes-with-parallel-change</link><guid isPermaLink="false">https://codeartify.substack.com/p/seamless-code-changes-with-parallel-change</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 02 Dec 2024 07:02:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;cfb102c8-bb99-4e47-b603-7db006692583&quot;,&quot;duration&quot;:null}"></div><h2>So your code doesn&#8217;t compile anymore (again)?</h2><p>I assume we all have been in this situation once in our software engineering career: we need to replace an old piece of code with a new one. This could be something as small as replacing a <code>List</code> with a stronger domain type like <code>CustomerAddresses</code>, or replacing an old SQL connection with a new NoSql database. Maybe you even need to replace an entire system with a new one. </p><p>Whatever the scale of the task, sooner than later, we find ourselves ripping out old code and trying to integrate our new code. Often, this is when the codebase does not compile anymore. Other teams may be pushing more features into main, which we&#8217;ll have to integrate into our non-compiling code mess. Thus, the complexity of the task increases continuously with every day we cannot merge our code. </p><p>Days may go by where we try to get our code to compile and our tests green again, but at some point, we may simply give up and revert it all. The complexity is just too high. If we cost 100$ an hour and spend 2 work weeks on it, we may have just burned through 8000$ or more in the process! That&#8217;s certainly not what our employer expects to pay for us for essentially accomplishing nothing at all! </p><p>Is there a better way to replace old with new that ensures our code always compiles, our tests remain always green, we can merge to main at any time, and continue changing our code at a later stage, should the product require us to work on something more urgent like a bug?</p><h2>Parallel Change to the Rescue!</h2><p>The technique that shines in replacing old with new code without breaking it in the process and which scales from variables to system level is called <strong>Parallel Change</strong>.</p><p>As far as I&#8217;m aware, the technique was famously illustrated by Joshua Kerievsky (Refactoring to Patterns/Industrial Logic), see e.g. <a href="https://www.infoq.com/presentations/The-Limited-Red-Society">here</a> around the 21 minutes mark. I highly recommend you have a look at that presentation as well.</p><h3>The Idea behind Parallel Change</h3><p>The idea behind Parallel Change has its origins in construction work. Imagine the task to refurbish or replace an old road. You cannot simply close down the entire road for a year or two. Instead, cars will still need to be able to continue driving on the old road while the new one is being build, even though there may be slow downs. The goal is to keep traffic running while at the same time refurbish the old road. </p><p>This is exactly what we want to achieve with our system: the user should not experience a complete shutdown. Some delays may be acceptable, but the system should continue running while behind the scenes it is being changed. So let&#8217;s investigate how Parallel Change ensures our code can always be merged to main.</p><h3>Parallel Change Workflow</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VL35!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VL35!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 424w, https://substackcdn.com/image/fetch/$s_!VL35!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 848w, https://substackcdn.com/image/fetch/$s_!VL35!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 1272w, https://substackcdn.com/image/fetch/$s_!VL35!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VL35!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png" width="1456" height="1558" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1558,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:539130,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VL35!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 424w, https://substackcdn.com/image/fetch/$s_!VL35!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 848w, https://substackcdn.com/image/fetch/$s_!VL35!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.png 1272w, https://substackcdn.com/image/fetch/$s_!VL35!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a5146e-10d6-4299-8857-c05db51d97d7_1720x1840.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><figcaption class="image-caption">Illustrating the flow from introducing the new structure, adding writes to it, switching reads from old to new, and removing the old structure using Parallel Change.</figcaption></figure></div><p>Parallel Change works as follows:</p><ol><li><p>Create the new piece of code you want to replace an old one with (with tests!).</p></li><li><p>Add the new piece of software right next to the old one.</p></li><li><p>For every write (<strong>command</strong>) to the old software, add a write to the new one, step-by-step, and run your tests after each addition.</p></li><li><p>Switch every read access (<strong>query</strong>) from the old piece of software to the new one, step-by-step, and run your tests after each switch.</p></li><li><p>Remove all the writes to the old software, step-by-step, and run your tests after each removal.</p></li><li><p>Remove the old piece of software.</p></li></ol><p>Step 3 ensures the state in both old and new pieces of software is the same, while in step 4, we will find out if we actually have the same state in both pieces. Until step 3, nothing should break, while in step 4, we potentially have a problem if we forgot any of the writes, so we need to have a strong test suite to validate if we have broken anything. Always run this test suite after a change!</p><p>Parallel Change allows you to commit after every step and know that the system still works! You can integrate immediately and change the system over a long period of time, sometimes years, without breaking a sweat. You could even replace entire systems that way. Traffic continues to flow even though there may be some obstacles and slowdowns on the way. Let&#8217;s now see a real code example (see also the video).</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If you liked this post so far, you may also like future posts where we go deeper into tactical domain-driven design and domain-driven refactoring! So to stay up-to-date:</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Parallel Change with a Simple Code Example</h2><p>To illustrate how you can apply Parallel Change in your codebase, I have prepared the following small example that you can also find in the <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parallel_change/Circle.java">repository</a>.</p><pre><code>public class Circle {
    private int x;
    private int y;
    private int radius;

    public Circle(int x, int y, int radius) {
        this.x = x;
        this.y = y;
       this.radius = radius;
    }

    public boolean contains(int x, int y) {
        return (x - this.x) * (x - this.x) 
               + (y - this.y) * (y - this.y) 
               &lt;= radius * radius;
    }

    public void moveTo(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void resize(int radius) {
       this.radius = radius;
    }
 
    public String format() {
       return "circle: {" +
             "\n\tcenter: (" + this.x + "," + this.y + ") " +
             "\n\tradius: " + this.radius + "\n}";
    }
}</code></pre><p>The goal is to replace <code>x</code> and <code>y</code> with a stronger <code>Point</code> record. The first step is to create and add a new instance of <code>Point</code> right next to the coordinates as <code>center</code>, see below.</p><pre><code><code>public record Point(int x, int y) {}</code></code></pre><pre><code>public class Circle {
    private int x;
    private int y;
    private Point center; // add center point
    // ...
}</code></pre><p>As a next step, we find all the places where x is written to and add an equivalent write operation to the point class. Because<code> x</code> and <code>y</code> always come in pairs, this will also solve writing the corresponding <code>y</code> value. However, our initial focus is on <code>x</code>. There are two places where <code>x</code> is written to, one in the constructor and one in the <code>moveTo</code> method, see below. </p><pre><code>public class Circle {
    private int x;
    private int y;
    private Point center;

    // ...

    public Circle(int x, int y, int radius) {
        this.x = x;
        this.y = y;
        this.center = new Point(x, y); // set center
        // ...
    }

    // ...

    public void moveTo(int x, int y) {
        this.x = x;
        this.y = y;
        this.center = new Point(x, y); // set center
    }</code></pre><p>We run our tests after each step. Up until now, nothing should break as we only added code. The <code>center</code> point should now always have the same state as <code>x</code> (and by coincidence, also <code>y</code>). In the next step, we will switch every call to get the value of <code>x </code>to a call to <code>center.x() </code>and run our tests every time we switch. Three places need to be adapted, two in the <code>contains</code> method and 1 in the <code>format</code> method.</p><pre><code>public class Circle { 

    // ...

    public boolean contains(int x, int y) {
        return (x - this.center.x()) // read center.x()
             * (x - this.center.x()) // read center.x()
             + (y - this.y) * (y - this.y) 
             &lt;= radius * radius;
    }

    // ...
 
    public String format() {
       return "circle: {" +
             "\n\tcenter: (" + this.center.x() // read center.x()
             + "," + this.y + ") " +
             "\n\tradius: " + this.radius
             + "\n}";
    }
}</code></pre><p>Now, <code>x</code> is not read from anymore, only from <code>center.x()</code>. We can now step by step remove writes to <code>x</code>, until the variable <code>x</code> is entirely dead code, and finally remove it. The resulting code looks as follows:</p><pre><code>
public class Circle {
    private int y;
    private Point center;
    private int radius;

    public Circle(int x, int y, int radius) {
        this.y = y;
        this.center = new Point(x, y);
        this.radius = radius;
    }

    public boolean contains(int x, int y) {
        return (x - this.center.x()) * (x - this.center.x()) 
             + (y - this.y) * (y - this.y) 
               &lt;= radius * radius;
    }

    public void moveTo(int x, int y) {
        this.y = y;
        this.center = new Point(x, y);
    }

    public void resize(int radius) {
       this.radius = radius;
    }
 
    public String format() {
       return "circle: {" +
               "\n\tcenter: (" + this.center.x() + "," + this.y + ") " 
            +  "\n\tradius: " + this.radius
             + "\n}";
    }
}</code></pre><p>We can now follow the same process to get rid of <code>y</code>. Step by step switch all reads from <code>y </code>to <code>center.y() </code>and run the tests after each step, then remove all the writes to <code>y</code>, and finally, remove the member variable <code>y</code>. Eventually, we arrive at the following code:</p><pre><code>public class Circle {
    private Point center;
    private int radius;

    public Circle(int x, int y, int radius) {
       this.center = new Point(x, y);
       this.radius = radius;
    }

    public boolean contains(int x, int y) {
        return (x - this.center.x()) * (x - this.center.x())
             + (y - this.center.y()) * (y - this.center.y())
               &lt;= radius * radius;
    }

    public void moveTo(int x, int y) {
        this.center = new Point(x, y);
    }

    public void resize(int radius) {
       this.radius = radius;
    }
 
    public String format() {
       return "circle: {" +
               "\n\tcenter: ("
               + this.center.x() + ","
               + this.center.y() + ") " +
             "\n\tradius: " + this.radius
             + "\n}";
    }
}</code></pre><p>Both <code>x</code> and <code>y</code> have been completely removed, the code always compiled, the tests where always green. We could commit at every step of the way, go home, merge into main, and nothing would have broken our code. </p><p>This algorithm scales from small examples to system levels and can also be used for example for database migrations. Give it a try! </p><p>If you want another example to practice, you could try to replace the <code>radius</code> variable with a strong type <code>Radius</code>. Have a look at the <a href="https://github.com/codeartify/examples/blob/main/src/main/java/com/codeartify/examples/parallel_change/Circle.java">repository</a> and the solution on the branch <code>solution_parallel_change</code>.</p><h2>How do I realise I need Parallel Change?</h2><p>When I first started with Parallel Change, I didn&#8217;t realise it&#8217;s full potential until I found myself time and time again in a broken system. Whenever it felt like &#8220;I never get that software to compile again&#8221;, I realised that I forgot about Parallel Change. So, the next time you find yourself in a situation where you end up with non-compiling code and analysis paralysis, remember not to get any <strong>SADER </strong>(pun intended ;)): </p><ol><li><p><strong>S</strong>et up the <em>new</em> structure</p></li><li><p><strong>A</strong>dd parallel writes to the <em>new</em><strong> </strong>structure</p></li><li><p><strong>D</strong>ivert reads from the <em>old</em> to the <em>new</em><strong> </strong>structure</p></li><li><p><strong>E</strong>nd writes to the <em>old</em> structure</p></li><li><p><strong>R</strong>emove the <em>old</em> structure</p></li></ol><p>Parallel Change will transform the way you approach complex code changes!</p><p>Have you experienced similar issues while changing code? What was your strategy to get over the issues of non-compiling code for a long time? </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/p/seamless-code-changes-with-parallel-change/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://codeartify.substack.com/p/seamless-code-changes-with-parallel-change/comments"><span>Leave a comment</span></a></p><p>If you like content like that, don&#8217;t forget to subscribe to stay up to date!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>Want to learn how to apply Parallel Change in Classic TDD to get from 1 to many? Check out our comprehensive<strong> <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">O&#8217;Reilly course</a> </strong>that demonstrates exactly that.</p><p>Want to learn how to write evolvable code? Visit our website<strong> <a href="http://www.codeartify.com/">www.codeartify.com</a> </strong>and get in touch with us! We provide worldwide remote and on-site workshops for you and your team!</p>]]></content:encoded></item><item><title><![CDATA[Refactor like a Pro: Part I - Essential Refactoring Tools and Techniques]]></title><description><![CDATA[How to refactor your code without breaking it in the process]]></description><link>https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials</link><guid isPermaLink="false">https://codeartify.substack.com/p/refactor-like-a-pro-part-i-essentials</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Tue, 26 Nov 2024 07:00:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/30240c1d-fd66-49b0-98b8-5b3dabdca403_1808x968.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;f8ead15a-1f15-4b5d-8ebc-3a89ca4f58a4&quot;,&quot;duration&quot;:null}"></div><p>Without the right techniques and tools, refactoring can become a nightmare. Code that does not compile for a long time, failing tests after we finally made it compile again, and bugs after we deploy the refactored code to production. </p><p>We may end up in analysis paralysis trying to figure out where our refactoring went wrong. In the worst case, we may need to revert weeks of changes because the codebase diverged so much. </p><p>It does not have to be that way. In this article, I want to demonstrate to you how adapt your way of thinking about refactoring and how to keep your code always in a compiling state with only little chance of introducing unwanted behaviours, using only 5 automated refactoring tools to do so.</p><h2>Refactor in Baby-Steps</h2><p>Your mindset should be that you only refactor one small thing, run your tests, and then commit. The more complex the refactoring goal, the smaller your step should be. </p><p>The goal is to always try to stay in a state of <em>flow</em>. If you notice that the [refactor step - test - commit] cycle becomes boring, you may add some additional steps before running tests again and committing. </p><p>On the other hand, if you refactor too much at once and end up with code that does not compile anymore or with failing tests, revert to the last state where all the tests passed and reduce the number of refactoring steps before you run the tests again and commit. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GlBR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GlBR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 424w, https://substackcdn.com/image/fetch/$s_!GlBR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 848w, https://substackcdn.com/image/fetch/$s_!GlBR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 1272w, https://substackcdn.com/image/fetch/$s_!GlBR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GlBR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png" width="1456" height="1084" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1084,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:167469,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GlBR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 424w, https://substackcdn.com/image/fetch/$s_!GlBR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 848w, https://substackcdn.com/image/fetch/$s_!GlBR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 1272w, https://substackcdn.com/image/fetch/$s_!GlBR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4a01c81-2005-4675-b166-b878778e75bd_1642x1222.png 1456w" sizes="100vw" fetchpriority="high"></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><figcaption class="image-caption">Try to stay around the green line of flow when you refactor. Complex refactoring tasks should be broken down into smaller steps. Commit after each successful test run to be able to revert easily when things go wrong.</figcaption></figure></div><h2>No Tests - No Refactoring!</h2><p>Before I show you how to apply the essential refactoring tools, I want to make clear that I assume that we have a <em>strong and fast test suite in place</em>, ideally unit tests, before we start refactoring. Else, we never know if we break something. If your code has no tests yet, you first need to create them. In a later article I will show you how to do that so stay tuned.</p><h2>The 5 Essential Automated Refactoring Tools </h2><p>There are only five automated refactoring tools your IDE needs to support to refactor effectively, which are:</p><p><em><strong>Rename</strong></em></p><p>The most powerful refactoring in our toolbox. Giving our variables, methods, or classes more expressive, context- and domain-specific names may already be enough to turn a completely unmaintainable piece of code into something easier to work with if we know the business domain this code is applied in. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cp9W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cp9W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 424w, https://substackcdn.com/image/fetch/$s_!cp9W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 848w, https://substackcdn.com/image/fetch/$s_!cp9W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 1272w, https://substackcdn.com/image/fetch/$s_!cp9W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cp9W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png" width="1558" height="174" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:174,&quot;width&quot;:1558,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:46765,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cp9W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 424w, https://substackcdn.com/image/fetch/$s_!cp9W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 848w, https://substackcdn.com/image/fetch/$s_!cp9W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 1272w, https://substackcdn.com/image/fetch/$s_!cp9W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff5feac6-8059-4d06-b4b7-1e5842607475_1558x174.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Before renaming c and r</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CApp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CApp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 424w, https://substackcdn.com/image/fetch/$s_!CApp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 848w, https://substackcdn.com/image/fetch/$s_!CApp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 1272w, https://substackcdn.com/image/fetch/$s_!CApp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CApp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png" width="1764" height="183" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:183,&quot;width&quot;:1764,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56663,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CApp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 424w, https://substackcdn.com/image/fetch/$s_!CApp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 848w, https://substackcdn.com/image/fetch/$s_!CApp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 1272w, https://substackcdn.com/image/fetch/$s_!CApp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8c132ea-3c27-4398-bbf3-3c5dba965100_1764x183.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">After renaming c and r to center and radius</figcaption></figure></div><p><em><strong>Extract Variable</strong></em></p><p>An essential tool in the refactoring toolbox is &#8220;extract variable&#8221;. It allows us to split a complex line of expressions, like those we may find in large and hard to understand if-statements, into smaller, more cohesive parts and give them domain-specific names. It is also often the prerequisite to split parts of the logic into smaller, cohesive modules, which is why it plays well with the next refactoring technique.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0xqR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0xqR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 424w, https://substackcdn.com/image/fetch/$s_!0xqR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 848w, https://substackcdn.com/image/fetch/$s_!0xqR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 1272w, https://substackcdn.com/image/fetch/$s_!0xqR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0xqR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png" width="1456" height="162" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:162,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:58361,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0xqR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 424w, https://substackcdn.com/image/fetch/$s_!0xqR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 848w, https://substackcdn.com/image/fetch/$s_!0xqR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 1272w, https://substackcdn.com/image/fetch/$s_!0xqR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34835b23-2372-4788-9f02-89f56a90ba8d_1656x184.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Extracting variables for deltaX and deltaY (duplications)</figcaption></figure></div><p><em><strong>Extract Method</strong></em></p><p>One of the most powerful refactoring techniques is &#8220;extract method/function&#8221;. In combination with extract variable, we can wrap small cohesive parts of the overall logic into methods with expressive, context-specific names.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!K2Az!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!K2Az!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 424w, https://substackcdn.com/image/fetch/$s_!K2Az!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 848w, https://substackcdn.com/image/fetch/$s_!K2Az!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 1272w, https://substackcdn.com/image/fetch/$s_!K2Az!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!K2Az!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png" width="1456" height="201" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/daac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:201,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63115,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!K2Az!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 424w, https://substackcdn.com/image/fetch/$s_!K2Az!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 848w, https://substackcdn.com/image/fetch/$s_!K2Az!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 1272w, https://substackcdn.com/image/fetch/$s_!K2Az!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaac3e56-b602-409d-96d7-a90d3c68ad8f_1548x214.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Extracting a method &#8220;square&#8221; for squaring values</figcaption></figure></div><p><em><strong>Inline</strong></em></p><p><em>Inlining</em> means copy-pasting the content of a variable, method, or other form of module where this variable or method was used before. If it was used in multiple places, it may create duplications. It&#8217;s the inverse of extract variable or extract method. It is an essential tool especially in code with suboptimal abstractions, so that we can easily start out with a green slate and refactor towards a more maintainable solution.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JRsI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JRsI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 424w, https://substackcdn.com/image/fetch/$s_!JRsI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 848w, https://substackcdn.com/image/fetch/$s_!JRsI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 1272w, https://substackcdn.com/image/fetch/$s_!JRsI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JRsI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png" width="1360" height="194" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:1360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53772,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JRsI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 424w, https://substackcdn.com/image/fetch/$s_!JRsI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 848w, https://substackcdn.com/image/fetch/$s_!JRsI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 1272w, https://substackcdn.com/image/fetch/$s_!JRsI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9321d640-0786-4690-a2ad-04bef76481b4_1360x194.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Inlining deltaX and deltaY again</figcaption></figure></div><p>Some IDEs like VSCode lack &#8220;inline&#8221; capabilities. However, it is absolutely essential to be able to try out different refactoring options quickly. I would always opt for an IDE like IntelliJ or Eclipse that supports &#8220;inline&#8221; out of the box.</p><p><em><strong>Move</strong></em></p><p>Extracting methods is not enough to improve the overall design. We also need to be able to split a long class or file into more cohesive parts and move parts to other files or classes. This is why it is extremely helpful if our IDE can automatically move methods to other classes. Although it can be done manually rather easily compared to extract variable/method or inline, I would still opt for an IDE that takes over most of the work as it&#8217;s just faster and safer to do so.</p><p><em>Lastly</em>, an IDE should be able to <em>create code automatically</em>. For example, if we declare a new class using new, a simple shortcut should allow us to create that class in a few simple steps. Doing it automatically reduces the time spent and error probability a lot.</p><h2>Shortcuts</h2><p>To get you started more easily, I have compiled a list of all shortcuts for Mac and Windows for both Jetbrains (IntelliJ) and Eclipse so that you don&#8217;t have to figure them out all by yourself. You can download it as PDF here:</p><div class="file-embed-wrapper" data-component-name="FileToDOM"><div class="file-embed-container-reader"><div class="file-embed-container-top"><image class="file-embed-thumbnail" src="https://substackcdn.com/image/fetch/w_400,h_600,c_fill,f_auto,q_auto:best,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6119d345-677a-465a-9f8c-43718484c624_1660x598.png"></image><div class="file-embed-details"><div class="file-embed-details-h1">Refactoring Shortcuts (Jetbrains, Eclipse)</div><div class="file-embed-details-h2">12KB &#8729; PDF file</div></div><a class="file-embed-button wide" href="https://codeartify.substack.com/api/v1/file/8a86dc6b-0f9f-4d4d-85fe-0ef0624c6c7e.pdf"><span class="file-embed-button-text">Download</span></a></div><div class="file-embed-description">All the shortcuts you need to refactor effectively</div><a class="file-embed-button narrow" href="https://codeartify.substack.com/api/v1/file/8a86dc6b-0f9f-4d4d-85fe-0ef0624c6c7e.pdf"><span class="file-embed-button-text">Download</span></a></div></div><h2>Conclusion</h2><p>Refactoring is a continuous process that we should be doing all the time while we develop software, not only in one big &#8220;refactoring story&#8221;. </p><p>To do so, we need to work in baby steps and commit after every green run of our tests. Without tests, we always run the risk of introducing bugs, so we need to ensure that we have a strong test suite.</p><p>There are 5 essential refactoring tools our IDE needs to support besides code generation - rename, extract variable, extract method, inline, and move.</p><p>Now that we know the essential tools for refactoring, we also need to know how to apply them effectively. I will dive into this in some of the next articles, so stay tuned!</p><p>If you want to test it yourself, you can find the code examples used in the video and post in the following <a href="https://github.com/codeartify/examples">repository</a> (solution with steps on branch refactoring_basics).</p><p>Do you have any questions or remarks on the topic of refactoring code? Write a comment and we can discuss it further!</p><p>If you like content like that, don&#8217;t forget to subscribe to stay up to date!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>Want to learn how to write evolvable code? Visit our website<strong> <a href="http://www.codeartify.com">www.codeartify.com</a> </strong>and get in touch with us! We provide worldwide remote and on-site workshops for you and your team!</p><p>Want to know the importance of a rich domain model? Check out our comprehensive<strong> <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">O&#8217;Reilly course</a> </strong>on Domain-Driven Design, Clean Architecture, EventStorming, and TDD!</p><p></p>]]></content:encoded></item><item><title><![CDATA[Testing each production class in isolation kills code evolution]]></title><description><![CDATA[Illustrated with a simple example]]></description><link>https://codeartify.substack.com/p/testing-each-production-class-in-isolation-kills-code-evolution</link><guid isPermaLink="false">https://codeartify.substack.com/p/testing-each-production-class-in-isolation-kills-code-evolution</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 11 Nov 2024 06:31:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4b88b64e-5d17-4d8b-acbb-4826046d1174_1530x946.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s something we see and hear over and over again. To achieve high quality code, some devs propose to write a test class for every production class in isolation. Every collaborator of the &#8220;SUT&#8221; (system under test) should then be replaced with a &#8220;mock&#8221; or test double to achieve this isolation. </p><p>In this article, I want to briefly outline with a simple example that you can try for yourself why this idea can destroy your code&#8217;s ability to change effectively and cheaply. </p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;e9a0e34c-ddb1-4ea0-94f2-325c24407ed3&quot;,&quot;duration&quot;:null}"></div><h2>A simple example</h2><p>Test code should only change if the <em>behaviour</em> of the production code changes. We should not need to adapt test code just because we restructured the internals of our public API.</p><p>Let&#8217;s imagine the following simple codebase. A service &#8220;AService&#8221; has one collaborator &#8220;BService&#8221; which is called in AService&#8217;s method &#8220;invoke()&#8221;, as shown below.</p><pre><code>public class AService {
    private final BService bService;

    public AService(BService bService) {
        this.bService = bService;
    }

    public String invoke() {
        // here is where the magic happens
        return this.bService.getHelloWorld();
    }
}</code></pre><pre><code>public class BService {
    private int callCounter = 0;

    public String getHelloWorld() {
        if (callCounter++ == 0) {
            return "Hello World";
        }
        return "World Hello";
    }
}</code></pre><p>Let&#8217;s write a test for AService where we use Mockito to stub BService&#8217;s getHelloWorld() call, and a test for BService&#8217;s getHelloWorld() method.</p><pre><code>public class AServiceTest {
    @Test
    void test1() {
        var mock = <em>mock</em>(BService.class);
        <em>when</em>(mock.getHelloWorld()).thenReturn("Hello World");

        var aService = new AService(mock);

        String result = aService.invoke();

        <em>assertEquals</em>("Hello World", result);
    }

    @Test
    void test2() {
        var mock = <em>mock</em>(BService.class);
        <em>when</em>(mock.getHelloWorld()).thenReturn("World Hello");

        var aService = new AService(mock);

        aService.invoke();
        String result = aService.invoke();

        <em>assertEquals</em>("World Hello", result);
    }
}</code></pre><pre><code>public class BServiceTest {
    @Test
    void test1() {
        var bService = new BService();

        var helloWorld = bService.getHelloWorld();

        <em>assertEquals</em>("Hello World", helloWorld);
    }

    @Test
    void test2() {
        var bService = new BService();

        bService.getHelloWorld();
        var helloWorld = bService.getHelloWorld();

        <em>assertEquals</em>("World Hello", helloWorld);
    }
}</code></pre><p>So far, so bad. What if at some point we want to inline getHelloWorld() into AService because the call to AService.invoke() actually does nothing except delegating to BService.getHelloWorld()? Both our test classes break! </p><pre><code>public class AServiceTest {
    @Test
    void test1() {
        var mock = <em>mock</em>(BService.class);

        // --------------------------------
        // automatic inline adds this
        // --------------------------------
        String result1 = "World Hello";
        if (mock.callCounter++ == 0) {
            result1 = "Hello World";
        }
        <em>when</em>(result1).thenReturn("Hello World");
        // --------------------------------

        var aService = new AService(mock);

        String result = aService.invoke();

        <em>assertEquals</em>("Hello World", result);
    }

    @Test
    void test2() {
        var mock = <em>mock</em>(BService.class);

        // --------------------------------
        // automatic inline adds this
        // --------------------------------
        String result1 = "World Hello";
        if (mock.callCounter++ == 0) {
            result1 = "Hello World";
        }
        <em>when</em>(result1).thenReturn("World Hello");
        // --------------------------------

        var aService = new AService(mock);

        aService.invoke();
        String result = aService.invoke();

        <em>assertEquals</em>("World Hello", result);
    }
}</code></pre><p>Of course, BServiceTest&#8217;s test methods for getHelloWorld() can now be deleted as they aren&#8217;t used anymore. But AServiceTest&#8217;s test double for BService needs to be adapted. We need to touch test code even though we haven&#8217;t changed the behaviour of the invoke() method.</p><p>Now let&#8217;s look at an alternative scenario where we have no test class for BService but only a test class for the public API of AService that does not rely on test doubles but instead injects the actual BService.</p><pre><code>public class AServiceBetterTest {

    @Test
    void test() {
        var aService = new AService(new BService());

        String result = aService.invoke();

        <em>assertEquals</em>("Hello World", result);
    }

    @Test
    void test2() {
        var aService = new AService(new BService());

        aService.invoke();
        String result = aService.invoke();

        <em>assertEquals</em>("World Hello", result);
    }
}</code></pre><p>If we inline the BService.getHelloWorld() method, the test code looks as follows:</p><pre><code>public class AServiceBetterTest {

    @Test
    void test() {
        var aService = new AService(new BService());

        String result = aService.invoke();

        <em>assertEquals</em>("Hello World", result);
    }

    @Test
    void test2() {
        var aService = new AService(new BService());

        aService.invoke();
        String result = aService.invoke();

        <em>assertEquals</em>("World Hello", result);
    }
}</code></pre><p>You may have noticed: <strong>nothing changed</strong>! Only if we adapt the public interface of AService&#8217;s constructor to remove BService, we need to touch the test code. We can mitigate this problem by hiding away on what internal collaborators AService depends using e.g. a creation method on AService.</p><pre><code>public class AServiceBetterTest {

    @Test
    void test() {
        var aService = AService.<em>create</em>();

        String result = aService.invoke();

        <em>assertEquals</em>("Hello World", result);
    }

    @Test
    void test2() {
        var aService = AService.<em>create</em>();

        aService.invoke();
        String result = aService.invoke();

        <em>assertEquals</em>("World Hello", result);
    }
}

public class AService {
    ...
    public static AService create() {
        // hide internal collaborators with creation methods
        return new AService(new BService());
    }
}</code></pre><p>With this in place, we can change the collaborators in the create() method however we like.</p><h2>Conclusion</h2><p>Even this extremely small codebase demonstrates why we should avoid testing every &#8220;public&#8221; (or even protected or private) method of collaborators that are only used internally by other services in isolation, and &#8220;mock away&#8221; collaborators. If you want to call these &#8220;sociable unit tests&#8221; or &#8220;larger unit tests&#8221;, the idea behind it is that you mainly <strong>test the public, deep interface of the service that actually accomplishes something for the external caller and avoid coupling test code to production code</strong>. </p><p>You may think of your production code as a library. Which classes and methods are exposed to the public (meaning, are out of your control once they&#8217;re released because you don&#8217;t know who the caller are going to be?) and which only contain the &#8220;<code>public</code>&#8221; keyword because you need to access these methods by another method of another class? </p><p>In our experience, the most flexible test cases target only the publicly exposed API. We want to test any possible input we can receive by a public (out of our control) caller. If an input combination is theoretically possible in an internal method but cannot be executed from the public API, there may actually be no need to write a test for it. </p><p>In our tests, we should try to avoid creating test doubles for our own production classes whenever possible. We should reserve test doubles for <strong>awkward dependencies</strong>. These are dependencies that are slow, hard to instantiate, or nondeterministic, like file-system-, I/O- and network access, databases, random number generators, time, etc. Any other class we have control over should be instantiated directly so that we can freely refactor the internals of our code without having to adapt any tests! Only if the actual behaviour changes should we need to touch a test.</p><p>As always, this is only a <strong>rule of thumb</strong> and there are many exceptions. </p><p><em>Sometimes it is not possible to test without test doubles, and sometimes our internal class is complex and has many edge cases that need to be covered by an own test class file</em>. </p><p>But it should <em>always</em> be a <strong>deliberate</strong> decision to create test doubles or to test &#8220;internal&#8221; &#8220;public&#8221; methods. </p><p>If you want to test it yourself, you can find the code examples used in the this <a href="https://github.com/codeartify/examples">repository</a>.</p><p>What do you think? Do you agree or disagree? Do you have other experiences to share that show the importance of mocking collaborators even if they are not awkward? Write a comment and we can discuss it further!</p><p>If you like content like that, don&#8217;t forget to subscribe to stay up to date!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.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://codeartify.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>Want to learn how to write evolvable code? Visit our website<strong> <a href="http://www.codeartify.com">www.codeartify.com</a> </strong>and get in touch with us! We provide worldwide remote and on-site workshops for you and your team!</p><p>New to Domain-Driven Design, Clean Architecture, EventStorming, and TDD? Check out our comprehensive<strong> <a href="https://learning.oreilly.com/course/domain-driven-design-event/0636920968672/">O&#8217;Reilly course</a> </strong>on that topic.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Technical Agile Coaching]]></title><description><![CDATA["Yet another coach" or vital addition on the way to high-performing teams?]]></description><link>https://codeartify.substack.com/p/technical-agile-coaching</link><guid isPermaLink="false">https://codeartify.substack.com/p/technical-agile-coaching</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Mon, 16 Sep 2024 05:33:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!n_kJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p>"We have Scrum Masters, Agile Coaches, Team Coaches, and now Technical Agile Coaches? Is there actually still somebody around who works productively?" I hear you say. But let me explain. </p><p>The idea for my interpretation of a "Technical Agile Coach", which subsequently will be referred to also as TACo, came to me when I first heard of <a href="https://sammancoaching.org/">Samman Technical Coaching</a>, a coaching technique developed by <a href="https://www.linkedin.com/in/emilybache/">Emily Bache</a>. The main idea is simple - as part of a development team, a TACo works together with the entire team and individuals on improving their agile software engineering skills.</p><p>These skills include, but are not limited to: eXtreme Programming, Refactoring, Testing and Test-Driven Development, identifying and solving Code Smells, software design like Hexagonal or Clean Architecture, Event Sourcing, CQRS, strategic and tactical Domain-Driven Design, EventStorming, Story Writing &amp; Slicing, effective Aggregate- and Monolith/Microservice-sizing, and many more. Teams have typically heard of these topics, but because there are so many things a modern software engineer needs to know (frameworks etc.), understandably, they do not always have the time and energy to invest in these methodological topics as well as much. Yet, they are key to effectively develop software.</p><p>Practices are taught in 1 - 2 hours called Learning Hours, which can be bi-weekly, weekly, every other day, daily, or even more frequently, depending on the need. Practices should be introduced depending on the interests and needs of the entire team. During Ensemble - or Pair Programming sessions, small groups or team members can address their interests and potentials for improvement individually. There is no obligation - every team member decides for themselves how much involvement they want with the TACo.</p><p>A TACo, on the other hand, can step-by-step help building up these skills on the job, while the team is productively developing software. By the end of a mandate, the understanding and skills of the team will have significantly broadened. Compared to singular (multi-day) workshops with little retention, continuously practicing technical software development skills is more likely to form long lasting habits. </p><h2>A TACo a Day keeps the Doctor away</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n_kJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n_kJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 424w, https://substackcdn.com/image/fetch/$s_!n_kJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 848w, https://substackcdn.com/image/fetch/$s_!n_kJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 1272w, https://substackcdn.com/image/fetch/$s_!n_kJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n_kJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png" width="1136" height="698" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:698,&quot;width&quot;:1136,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:754038,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!n_kJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 424w, https://substackcdn.com/image/fetch/$s_!n_kJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 848w, https://substackcdn.com/image/fetch/$s_!n_kJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 1272w, https://substackcdn.com/image/fetch/$s_!n_kJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f70a4d6-da70-40e3-a99a-80e27bc6c592_1136x698.png 1456w" sizes="100vw" fetchpriority="high"></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>However, a TACo does not only address technical skills. A development team can technically excel, yet be riddled with unresolved internal problems and external pressures that can destroy all the good work done so far.</p><p>As such, technical agile coaching is an effective approach to identify and address the actual, underlying blockers of a team. As part of the team, a TACo feels the internal quarrels and outside pressures, but because they are not immediately involved in productive work, they are in the unique position to address issues without being directly affected. As a consultant to the team, a TACo may point out potentials for improvement, but the team is free to decide to pursue them (immediately) or not.</p><p>"Technical Agile Coach" is also not a typical "leader" role. There is no hierarchical structure in place as the TACo is neither above nor below, but besides a team's and an organisation's hierarchy. Any team member from junior to senior over PO to ScM can seek inputs from a TACo without fear of influencing their career in any way.  Anything mentioned in personal conversations is handled confidential unless team members want actions to be taken. </p><p>Of course, this does not imply that a TACo should ignore pressing issues like mobbing or company-harming practices! On the contrary, due to their unique position, they are able to identify and address such issues even earlier within the team and provide guidance or get input from outside without escalating the entire situation out of proportion.</p><h2>Best TACo Recipe</h2><p>Overall, technical agile coaching is not an imposed, top-down approach. Neither is it a "visit, fire and forget" approach, where a TACo only shows up for some workshop without any investment in the team and then leaves again. It requires both a high degree of technical understanding, hard programming skills, but also the abilities to "feel the room" effectively, avoid position taking, and adapt one's manners according to each individual team member. TACos enable the team to work better individually and collectively.</p><p>The highest value of this role comes from the deep involvement within the team, while being detached from outside influences and pressures. TACos should therefore always be treated as separated from the hierarchical organisation of a company, as an incorporation into it would defeat the purpose of the role.</p><p>As a young role, its effectiveness cannot be put into numbers yet. But the close involvement of a TACo within a team with a steady focus on identifying root causes of problems and developing a team-tailored set of possible solutions, should logically lead to a more effective outcome than one-time workshops or presentations with only little team involvement. </p><p>Additionally, this role provides an interesting career opportunity for any developer that does not want to pursue a purely low-level, technical path, but at the same time does not want to leave the technical aspects behind entirely in favour of a classic leadership role, either. It involves skills from all the different roles, from Scrum Master to Agile Coach to Developer to Tech Lead and Architect and even PO, as well as a high degree of social skills. It's for skilled generalists who are interested in various topics and the global picture.</p><p>Furthermore, TACos are connected throughout the company and can bring in required skills from outside the team if needed. They should best be deeply connected outside of the company and internationally as well to always stay up to date and be able to exchange and learn from various other experts, approaches, views and ideas.</p><p>It's more than a job, it's a calling.</p><p>If you want to learn more about my approach on technical agile coaching, just DM me, e.g. on <a href="https://www.linkedin.com/in/oliver-zihler/">Linkedin</a>. If you want to exchange with a TACo for your team&#8217;s specific needs, we at <a href="http://www.codeartify.com">Codeartify</a> are happy to take on the challenge as well! See you soon!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Oliver&#8217;s Software Craftsmanship &amp; Software Engineering Stack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[From Layered to Hexagonal Architecture in 2 steps]]></title><description><![CDATA[A quick guide]]></description><link>https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture</link><guid isPermaLink="false">https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture</guid><dc:creator><![CDATA[Oliver Zihler]]></dc:creator><pubDate>Wed, 07 Feb 2024 07:20:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!k5HP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Hexagonal Architecture?</h2><p>You may have heard the terms "Hexagonal Architecture" or "Ports and Adapters", coined by Alistair Cockburn, in some form or another. It's an architectural design pattern that places the business rules at its core. The idea is that the business rules are what defines a company, not technical details like what kind of presentation or database technology is used. But how do we get from a classic layered architecture to Hexagonal Architecture?&nbsp;</p><h2>Layered Architecture in a Nutshell</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k5HP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k5HP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 424w, https://substackcdn.com/image/fetch/$s_!k5HP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 848w, https://substackcdn.com/image/fetch/$s_!k5HP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 1272w, https://substackcdn.com/image/fetch/$s_!k5HP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k5HP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png" width="585" height="503" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:503,&quot;width&quot;:585,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61733,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k5HP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 424w, https://substackcdn.com/image/fetch/$s_!k5HP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 848w, https://substackcdn.com/image/fetch/$s_!k5HP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 1272w, https://substackcdn.com/image/fetch/$s_!k5HP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65958f9-9ecd-46e3-bb5d-7992a49934c4_585x503.png 1456w" sizes="100vw" fetchpriority="high"></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>In a classic layered architecture, we typically find the following layers: Presentation --&gt; Application --&gt; Data Access. Upper layers depend on lower layers. All the layers however, depend on the data access layer.&nbsp; This means that if we change the data access technology, say from SQL to an external system, we need to adapt the code of layers above, even though they did not change in functionality.&nbsp;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Oliver&#8217;s Software Craftsmanship &amp; Software Engineering Stack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><pre><code><code>@RestController
class RestCustomerController {
  CustomerService service

  @PostMapping("/customer/name")
  CustomerDbEntity changeCustomerName(CustomerDbEntity dbEntity) {
    return service.changeCustomerName(dbEntity);
  }
}

@Service
class CustomerService {
  SqlDbClient client

  public CustomerDbEntity changeCustomerName(CustomerDbEntity input) {
    CustomerDbEntity entity = client.execute(
       "select * from customer where id="+input.id);
    CustomerDbEntity result = applySomeBusinessRules(entity, input);
    return client.execute(
        "update customer set name =" +result.name +" where 
        id="+result.id);
  }
}</code></code></pre><h2>From Layered to Hexagonal Architecture in 2 Steps</h2><p>Now, let's see how we can transition from this layered architecture to a hexagonal architecture.</p><h2>Step 1 - Invert the Dependencies of the Application Service to the Data Access layer</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DzL4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DzL4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 424w, https://substackcdn.com/image/fetch/$s_!DzL4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 848w, https://substackcdn.com/image/fetch/$s_!DzL4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 1272w, https://substackcdn.com/image/fetch/$s_!DzL4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DzL4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png" width="1456" height="681" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:681,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:281983,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DzL4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 424w, https://substackcdn.com/image/fetch/$s_!DzL4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 848w, https://substackcdn.com/image/fetch/$s_!DzL4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.png 1272w, https://substackcdn.com/image/fetch/$s_!DzL4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6667a1-f792-4e8a-93db-846f89ef2b26_1893x886.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>The first step is to make the data access layer depend on the application layer, not the other way around. We can achieve this by introducing an interface that only uses application-specific data structures in its signature for CRUD operations. For that, a Customer class may be created, which could typically be a domain class that can also&nbsp;execute&nbsp;critical business rules. The important idea here is that the signature of the interface does not contain any CustomerDbEntity. The interface is application-layer specific. It's the first output&nbsp;<strong>port&nbsp;</strong>that is used by the CustomerService to load and store Customers. On the other hand, SqlCustomerRepository needs to implement this interface. It takes a Customer object, maps it to the CustomerDbEntity, invokes the db client, and potentially maps the CustomerDbEntity back to a Customer. Thus, it&nbsp;<strong>adapts</strong> the DB data structure from and to the application-specific Customer data structure. It's an&nbsp;<strong>adapter</strong>. Also, the service does not use CustomerDbEntity in its public method signatures anymore, but only simple application-layer-specific DTOs like CustomerData that get passed to and returned from the service. In pseudocode:</p><pre><code><code>interface CustomerRepository {
  Customer getById(String id);
  Customer update(Customer customer);
}

@Service
class CustomerService {
  CustomerRepository customers;

  public CustomerData changeCustomerName(NameData input) {
    Customer customer = customers.getById(input.id);

    customer.changeNameTo(input.name);

    Customer updatedCustomer = customers.update(customer);

    return toData(updatedCustomer);
  }
}

@Repository
class SqlCustomerRepository implements CustomerRepository {
  SqlDbClient client;

  Customer getById(String id) {
    CustomerDbEntity entity = client.execute(
        "select * from customer where id="+input.id);
    return toCustomer(entity);
  }

  public Customer update(Customer input) {
    CustomerDbEntity entity = client.execute(
        "update customer set name =" +result.name +" where 
        id="+result.id);
    return toCustomer(entity);
  }
}</code></code></pre><p>We could now easily implement a fake CustomerRepository for testing purposes:</p><pre><code><code>class InMemoryCustomerRepository implements CustomerRepository {
  Map&lt;String, Customer&gt; customers;

  Customer getById(String id) { return customers.get(id); }
  Customer update(Customer customer) {
    customers.put(customer);
    return customer;
  }
}</code></code></pre><h2>Step 2 - Segregate the Public Methods of the Application Service into Separate Interfaces</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iDnk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iDnk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 424w, https://substackcdn.com/image/fetch/$s_!iDnk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 848w, https://substackcdn.com/image/fetch/$s_!iDnk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 1272w, https://substackcdn.com/image/fetch/$s_!iDnk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iDnk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png" width="1456" height="570" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:570,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:408963,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iDnk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 424w, https://substackcdn.com/image/fetch/$s_!iDnk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 848w, https://substackcdn.com/image/fetch/$s_!iDnk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.png 1272w, https://substackcdn.com/image/fetch/$s_!iDnk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeea7f09-f21c-49c0-9de3-8ddd0ba6203b_2106x825.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>The second step involves hiding away how the different public methods of a generic application service are implemented from the presentation layer. This could be useful if we wanted to split a larger service into smaller use cases. By adding an interface for every public use case method that the CustomerService provides, and letting it implement them all, the RestCustomerController gets more fine-granular methods to execute. The controller may or may not use an own DTO instead of the&nbsp;data structures provided by the application layer in the CustomerService's public methods. That way, it may evolve independently from the application layer, for example if not all the fields need to be returned or they should be formatted already on the server, etc. These interfaces correspond to input&nbsp;<strong>ports</strong>, and the controller is a&nbsp;<strong>driving adapter</strong> that maps incoming data to the input port's data requirements, executes the functions of these ports, and maps data back to the caller's data format. In pseudocode:&nbsp;</p><pre><code><code>interface ChangeCustomerName {
   CustomerData changeNameTo(NameData name);
}

interface ChangeCustomerAddress {
   CustomerData changeAddressTo(AddressData address);
}

interface ChangeCustomerProfile {
   CustomerData changeProfileTo(CustomerProfileData profile);
}

@RestController
class RestCustomerController {
  ChangeCustomerName changeCustomerName;
  ChangeCustomerAddress changeCustomerAddress;
  ChangeCustomerProfile changeCustomerProfile;

  @PostMapping("/customer/name")
  CustomerDto changeCustomerName(NameDto dto) {
    NameData data = toData(dto);
    CustomerData customer = changeCustomerName.changeNameTo(data);
    return toDto(customer);
  }

  @PostMapping("/customer/address")
  CustomerDto changeCustomerAddress(AddressDto dto) {
    AddressData data = toData(dto);
    CustomerData customer = changeCustomerAddress.changeAddressTo(data);
    return toDto(customer);
  }

  @PostMapping("/customer/profile")
  CustomerDto changeCustomerProfile(ProfileDto dto) {
    ProfileData data = toData(dto);
    CustomerData customer = changeCustomerProfile.changeProfileTo(data);
    return toDto(customer);
  }
}

@Service
class CustomerService
  implements 
  ChangeCustomerName, ChangeCustomerAddress, ChangeCustomerProfile {

   @Override
   CustomerData changeNameTo(NameData name){...}
   @Override
   CustomerData changeAddressTo(AddressData address) {...}
   @Override
   CustomerData changeProfileTo(CustomerProfileData profile) {...}
}</code></code></pre><h2>That's it, basically</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J4lT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J4lT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 424w, https://substackcdn.com/image/fetch/$s_!J4lT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 848w, https://substackcdn.com/image/fetch/$s_!J4lT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!J4lT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J4lT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png" width="1456" height="811" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:811,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:582565,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J4lT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 424w, https://substackcdn.com/image/fetch/$s_!J4lT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 848w, https://substackcdn.com/image/fetch/$s_!J4lT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!J4lT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56f4e82f-538f-49c3-b57a-f443a3aceeb4_2679x1492.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>The controller adapter now uses any of the three input ports of the application layer and does not know of the CustomerService anymore, which implements the 3 port interfaces instead. Similarly, the CustomerService only uses output ports and does not know of the SqlCustomerRepository and only interacts with the output port interface CustomerRepository methods. There is even a Customer class that can be used to implement critical business rules on, which&nbsp;could be stored within an own "domain" layer.&nbsp;The domain layer is not strictly Ports &amp; Adapters anymore but actually Domain-Driven Design. Data access and presentation now depend on the application layer. All dependencies (arrows) point towards this application layer. This is why hexagonal architecture is a business-centric architecture. The different data structures may feel like an overkill for simple applications - they are. Their value comes especially in complex architectures, where presentation, application, and data access layers change independently, often. They are not required by Ports &amp; Adapters either, as long as the application does not depend on any data structure from the outside world. It can only know internal data structures.</p><p>What do you think about this architectural design pattern? Have you used it? To what success? What downsides do you see?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Oliver&#8217;s Software Craftsmanship &amp; Software Engineering Stack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://codeartify.substack.com/p/from-layered-to-hexagonal-architecture?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item></channel></rss>