<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Hexagonal Architecture - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Hexagonal Architecture - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 27 Jul 2026 15:23:10 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/hexagonal-architecture/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Implement a Hexagonal Architecture ]]>
                </title>
                <description>
                    <![CDATA[ By Bertil Muth A hexagonal  architecture simplifies deferring or changing technology decisions. You  want to change to a different framework? Write a new adapter. You want  to use a database, instead of storing data in files? Again, write an  adapter... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/implementing-a-hexagonal-architecture/</link>
                <guid isPermaLink="false">66d45dde55db48792eed3f43</guid>
                
                    <category>
                        <![CDATA[ Clean Architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Hexagonal Architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 19 Jun 2019 21:54:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/aluminum-architecture-art-1492232.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Bertil Muth</p>
<p>A hexagonal  architecture simplifies deferring or changing technology decisions. You  want to change to a different framework? Write a new adapter. You want  to use a database, instead of storing data in files? Again, write an  adapter for it.</p>
<p>Draw a boundary around the business logic. The hexagon. Anything inside the hexagon must be free from technology concerns.<br> The  outside of the hexagon talks with the inside only by using interfaces,  called ports. Same the other way around. By changing the implementation  of a port, you change the technology.</p>
<p>Isolating  business logic inside the hexagon has another benefit. It enables  writing fast, stable tests for the business logic. They do not depend on  web technology to drive them, for example.</p>
<p>Here’s  an example diagram. It shows Spring MVC technology as boxes with dotted  lines, ports and adapters as solid boxes, and the hexagon without its  internals:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/grafik.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>An adapter translates between a specific technology and a technology free port. The <code>PoemController</code> adapter on the left receives requests and sends commands to the <code>IReactToCommands</code> port. The <code>PoemController</code> is a regular Spring MVC Controller. Because it actively uses the port, it's called a driver adapter.</p>
<p><code>IReactToCommands</code> is called a driver port. Its implementation is inside the hexagon. It's not shown on the diagram.</p>
<p>On the right side, the <code>SpringMvcPublisher</code> adapter implements the <code>IWriteLines</code> port. This time, the <em>hexagon</em> calls the adapter through the port. That's why <code>SpringMvcPublisher</code> is called a driven adapter. And <code>IWriteLines</code> is called a driven port.</p>
<p>I show you how to implement that application. We go all the way from a  user story to a domain model inside the hexagon. We start with a simple  version of the application that prints to the console. Then we switch  to Spring Boot and Spring MVC.</p>
<h2 id="heading-from-a-user-story-to-ports-amp-adapters">From a user story to ports &amp; adapters</h2>
<p>The company FooBars.io decides to build a Poetry App. The product owner and the developers agree on the following user story:</p>
<p>As a reader<br>I want to read at least one poem each day<br>So that I thrive as a human being</p>
<p>As acceptance criteria, the team agrees on:</p>
<ul>
<li>When the user asks for a poem in a specific language, the system displays a random poem in that language in the console</li>
<li>It's ok to "simulate" the user at first, i.e. no real user interaction. (This will change in future versions.)</li>
<li>Supported languages: English, German</li>
</ul>
<p>The developers meet and draw the following diagram:</p>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4a_F9pCz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/02hr6f652yran0dz38h1.PNG" alt="poem-hexagon" width="600" height="400" loading="lazy"></p>
<p>So the <code>SimulatedUser</code> sends commands to the <code>IReactToCommands</code> port. It asks for poems in English and German. Here's the code, it's available on <a target="_blank" href="https://github.com/bertilmuth/poem-hexagon">Github</a>.</p>
<p>_poem/simple/driver_adapter/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/simple/driver_adapter/SimulatedUser.java">SimulatedUser.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SimulatedUser</span> </span>{
    <span class="hljs-keyword">private</span> IReactToCommands driverPort;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SimulatedUser</span><span class="hljs-params">(IReactToCommands driverPort)</span> </span>{
        <span class="hljs-keyword">this</span>.driverPort = driverPort;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
        driverPort.reactTo(<span class="hljs-keyword">new</span> AskForPoem(<span class="hljs-string">"en"</span>));
        driverPort.reactTo(<span class="hljs-keyword">new</span> AskForPoem(<span class="hljs-string">"de"</span>));
    }
}
</code></pre>
<p>The <code>IReactToCommands</code> port has only one method to receive any kind of command.</p>
<p>_poem/boundary/driver_port/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/driver_port/IReactToCommands.java">IReactToCommands.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IReactToCommands</span></span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">reactTo</span><span class="hljs-params">(Object command)</span></span>;
}
</code></pre>
<p><code>AskForPoem</code> is the command. Instances are simple, immutable POJOs. They carry the language of the requested poem.</p>
<p><em>poem/command/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/command/AskForPoem.java">AskForPoem.java</a></em></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AskForPoem</span> </span>{
    <span class="hljs-keyword">private</span> String language;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AskForPoem</span><span class="hljs-params">(String language)</span> </span>{
        <span class="hljs-keyword">this</span>.language = language;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getLanguage</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> language;
    }
}
</code></pre>
<p>And that's it for the left, driver side of the hexagon. On to the right, driven side.</p>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cMUjGG4H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8vsbpug5fjfjzs8sfs2y.PNG" alt="poem-hexagon: driven side up next" width="600" height="400" loading="lazy"></p>
<p>When the <code>SimulatedUser</code> asks the <code>IReactToCommands</code> port for a poem, the hexagon:</p>
<ol>
<li>Contacts the <code>IObtainPoems</code> port for a collection of poems</li>
<li>Picks a random poem from the collection</li>
<li>Tells the <code>IWriteLines</code> port to write the poem to the output device</li>
</ol>
<p>You can't see Step 2 yet. It happens inside the hexagon, in the  domain model. That's the business logic of the example. So we focus on  Step 1 and Step 3 first.</p>
<p>In Step 1, the collection of poems is a language dependent, hard coded array. It's provided by the <code>HardcodedPoemLibrary</code> adapter that implements the <code>IObtainPoems</code> port.</p>
<p>_poem/boundary/driven_port/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/driven_port/IObtainPoems.java">IObtainPoems.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IObtainPoems</span> </span>{
    String[] getMePoems(String language);
}
</code></pre>
<p>_poem/simple/driven_adapter/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/simple/driven_adapter/HardcodedPoemLibrary.java">HardcodedPoemLibrary.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HardcodedPoemLibrary</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IObtainPoems</span> </span>{
    <span class="hljs-keyword">public</span> String[] getMePoems(String language) {
        <span class="hljs-keyword">if</span> (<span class="hljs-string">"de"</span>.equals(language)) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String[] { <span class="hljs-comment">/* Omitted for brevity */</span> };
        } <span class="hljs-keyword">else</span> { 
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String[] { <span class="hljs-comment">/* Omitted for brevity */</span> };
        }
    }
}
</code></pre>
<p>In Step 3, the <code>ConsoleWriter</code> adapter writes the lines of the poems to the output device, i.e. the console.</p>
<p>_poem/boundary/driven_port/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/driven_port/IWriteLines.java">IWriteLines.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IWriteLines</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">writeLines</span><span class="hljs-params">(String[] strings)</span></span>;
}
</code></pre>
<p>_poem/simple/driven_adapter/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/simple/driven_adapter/ConsoleWriter.java">ConsoleWriter.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConsoleWriter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IWriteLines</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">writeLines</span><span class="hljs-params">(String[] lines)</span> </span>{
        Objects.requireNonNull(lines);
        <span class="hljs-keyword">for</span> (String line : lines) {
            System.out.println(line);
        }
        System.out.println(<span class="hljs-string">""</span>);
    }
}
</code></pre>
<p>We have created all the ports, and a simple implementation of all the  adapters. So far, the inside of the hexagon remained a mystery. It's up  next.</p>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s---tA0dZqp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/efcfrsrwb9jei5uik63k.PNG" alt="poem-hexagon: inside up next" width="600" height="400" loading="lazy"></p>
<h1 id="heading-command-handlers-inside-the-hexagon">Command handlers (inside the hexagon)</h1>
<p>When a user asks for a poem, the system displays a random poem.<br>Similar in the code: when the <code>IReactToCommands</code> port receives an <code>AskForPoem</code>command, the hexagon calls a <code>DisplayRandomPoem</code> command handler.</p>
<p>The <code>DisplayRandomPoem</code> command handler obtains a list of  poems, picks a random one and writes it to the output device. This is  exactly the list of steps we talked about in the last clause.</p>
<p>_poem/boundary/internal/command_handler/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/internal/command_handler/DisplayRandomPoem.java">DisplayRandomPoem.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DisplayRandomPoem</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Consumer</span>&lt;<span class="hljs-title">AskForPoem</span>&gt; </span>{
        <span class="hljs-comment">/* Omitted for brevity */</span>

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">accept</span><span class="hljs-params">(AskForPoem askForPoem)</span> </span>{
        List&lt;Poem&gt; poems = obtainPoems(askForPoem);
        Optional&lt;Poem&gt; poem = pickRandomPoem(poems);
        writeLines(poem);   
    }

        <span class="hljs-comment">/* Rest of class omitted for brevity */</span>
}
</code></pre>
<p>It's also the job of the command handler to translate between the domain model data and the data used in the port interfaces.</p>
<h1 id="heading-tying-commands-to-command-handlers">Tying commands to command handlers</h1>
<p>In my implementation of a hexagonal architecture, there is only a single driver port, <code>IReactToCommands</code>. It reacts to all types of commands.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IReactToCommands</span></span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">reactTo</span><span class="hljs-params">(Object command)</span></span>;
}
</code></pre>
<p>The <code>Boundary</code> class is the implementation of the <code>IReactToCommands</code> port. It creates a behavior model using a <a target="_blank" href="https://github.com/bertilmuth/requirementsascode">library</a>. The behavior model maps each command type to a command handler. Then, a behavior dispatches the commands based on the behavior model.</p>
<p><em>poem/boundary/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/Boundary.java">Boundary.java</a></em></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Boundary</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IReactToCommands</span>, <span class="hljs-title">BehaviorModel</span> </span>{
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> IObtainPoems poemObtainer;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> IWriteLines lineWriter;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> StatelessBehavior behavior;

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Class&lt;AskForPoem&gt; asksForPoem = AskForPoem.class;

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Boundary</span><span class="hljs-params">(IObtainPoems poemObtainer, IWriteLines lineWriter)</span> </span>{
    <span class="hljs-keyword">this</span>.poemObtainer = poemObtainer;
    <span class="hljs-keyword">this</span>.lineWriter = lineWriter;
    <span class="hljs-keyword">this</span>.behavior = StatelessBehavior.of(<span class="hljs-keyword">this</span>);
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> Model <span class="hljs-title">model</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> Model.builder()
        .user(asksForPoem).system(displaysRandomPoem())
        .build();
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">reactTo</span><span class="hljs-params">(Object commandObject)</span> </span>{
    behavior.reactTo(commandObject);
  }

  <span class="hljs-function"><span class="hljs-keyword">private</span> Consumer&lt;AskForPoem&gt; <span class="hljs-title">displaysRandomPoem</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DisplayRandomPoem(poemObtainer, lineWriter);
  }
}
</code></pre>
<h1 id="heading-the-domain-model">The domain model</h1>
<p>The domain model of the example doesn’t have very interesting functionality. The <a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/internal/domain/RandomPoemPicker.java">RandomPoemPicker</a> picks a random poem from a list.</p>
<p>A <a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/boundary/internal/domain/Poem.java">Poem</a> has a constructor that takes a String containing line separators, and splits it into verses.</p>
<p>The really interesting bit about the example domain model: it doesn’t  refer to a database or any other technology, not even by interface!</p>
<p>That means that you can test the domain model with <a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/test/java/poem/boundary/internal/domain/RandomPoemPickerTest.java">plain unit tests</a>. You don’t need to mock anything.</p>
<p>Such a pure domain model is not a necessary property of an  application implementing a hexagonal architecture. But I like the  decoupling and testability it provides.</p>
<h1 id="heading-plug-adapters-into-ports-and-thats-it">Plug adapters into ports, and that's it</h1>
<p>A final step remains to make the application work. The application  needs a main class that creates the driven adapters. It injects them  into the boundary.<br>It then creates the driver adapter,  for the boundary, and runs it.</p>
<p><em>poem/simple/<a target="_blank" href="https://github.com/bertilmuth/poem-hexagon/blob/master/src/main/java/poem/simple/Main.java">Main.java</a></em></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        <span class="hljs-keyword">new</span> Main().startApplication();
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startApplication</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Instantiate driven, right-side adapters</span>
        HardcodedPoemLibrary poemLibrary = <span class="hljs-keyword">new</span> HardcodedPoemLibrary();
        ConsoleWriter consoleWriter = <span class="hljs-keyword">new</span> ConsoleWriter();

        <span class="hljs-comment">// Inject driven adapters into boundary</span>
        Boundary boundary = <span class="hljs-keyword">new</span> Boundary(poemLibrary, consoleWriter);

        <span class="hljs-comment">// Start the driver adapter for the application</span>
        <span class="hljs-keyword">new</span> SimulatedUser(boundary).run();
    }
}
</code></pre>
<p>And that's it! The team shows the result to the product owner. And  she's happy with the progress. Time for a little celebration.</p>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PDHorQ0r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6pe5yam3xe68m11bojff.PNG" alt="hexagon-poem the completed application" width="600" height="400" loading="lazy"></p>
<h1 id="heading-switching-to-spring">Switching to Spring</h1>
<p>The team decides to turn the poem app into a web application. And to  store poems in a real database. They agree to use the Spring framework  to implement it.<br>Before they start coding, the team meets and draws the following diagram:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/grafik-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Instead of a <code>SimulatedUser</code>, there is a <code>PoemController</code> now, that sends commands to the hexagon.</p>
<p>_poem/springboot/driver_adapter/<a target="_blank" href="https://github.com/bertilmuth/poem-springboot/blob/master/src/main/java/poem/springboot/driver_adapter/PoemController.java">PoemController.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PoemController</span> </span>{
    <span class="hljs-keyword">private</span> SpringMvcBoundary springMvcBoundary;

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PoemController</span><span class="hljs-params">(SpringMvcBoundary springMvcBoundary)</span> </span>{
        <span class="hljs-keyword">this</span>.springMvcBoundary = springMvcBoundary;
    }

    <span class="hljs-meta">@GetMapping("/askForPoem")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">askForPoem</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(name = "lang", required = false, defaultValue = "en")</span> String language,
            Model webModel)</span> </span>{
        springMvcBoundary.basedOn(webModel).reactTo(<span class="hljs-keyword">new</span> AskForPoem(language));

        <span class="hljs-keyword">return</span> <span class="hljs-string">"poemView"</span>;
    }
}
</code></pre>
<p>When receiving a command, the <code>PoemController</code> calls <code>springMvcBoundary.basedOn(webModel)</code>. This creates a new <code>Boundary</code> instance, based on the <code>webModel</code> of the request:</p>
<p><em>poem/springboot/boundary/<a target="_blank" href="https://github.com/bertilmuth/poem-springboot/blob/master/src/main/java/poem/springboot/boundary/SpringMvcBoundary.java">SpringMvcBoundary.java</a></em></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpringMvcBoundary</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> IObtainPoems poemObtainer;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SpringMvcBoundary</span><span class="hljs-params">(IObtainPoems poemObtainer)</span> </span>{
        <span class="hljs-keyword">this</span>.poemObtainer = poemObtainer;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> IReactToCommands <span class="hljs-title">basedOn</span><span class="hljs-params">(Model webModel)</span> </span>{
        SpringMvcPublisher webPublisher = <span class="hljs-keyword">new</span> SpringMvcPublisher(webModel);
        IReactToCommands boundary = <span class="hljs-keyword">new</span> Boundary(poemObtainer, webPublisher);
        <span class="hljs-keyword">return</span> boundary;
    }
}
</code></pre>
<p>The call to <code>reactTo()</code> sends the command to the boundary, as before. On the right side of the hexagon, the <code>SpringMvcPublisher</code> adds an attribute <code>lines</code> to the Spring MVC model. That's the value Thymeleaf uses to insert the lines into the web page.</p>
<p>_poem/springboot/driven_adapter/<a target="_blank" href="https://github.com/bertilmuth/poem-springboot/blob/master/src/main/java/poem/springboot/driven_adapter/SpringMvcPublisher.java">SpringMvcPublisher.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpringMvcPublisher</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IWriteLines</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String LINES_ATTRIBUTE = <span class="hljs-string">"lines"</span>;

    <span class="hljs-keyword">private</span> Model webModel;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SpringMvcPublisher</span><span class="hljs-params">(Model webModel)</span> </span>{
        <span class="hljs-keyword">this</span>.webModel = webModel;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">writeLines</span><span class="hljs-params">(String[] lines)</span> </span>{
        Objects.requireNonNull(lines);
        webModel.addAttribute(LINES_ATTRIBUTE, lines);
    }
}
</code></pre>
<p>The team also implements a <code>PoemRepositoryAdapter</code> to access the <code>PoemRepository</code>. The adapter gets the <code>Poem</code> objects from the database. It returns the texts of all poems as a String array.</p>
<p>_poem/springboot/driven_adapter/<a target="_blank" href="https://github.com/bertilmuth/poem-springboot/blob/master/src/main/java/poem/springboot/driven_adapter/PoemRepositoryAdapter.java">PoemRepositoryAdapter.java</a>_</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PoemRepositoryAdapter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IObtainPoems</span> </span>{
    <span class="hljs-keyword">private</span> PoemRepository poemRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PoemRepositoryAdapter</span><span class="hljs-params">(PoemRepository poemRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.poemRepository = poemRepository;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-keyword">public</span> String[] getMePoems(String language) {
        Collection&lt;Poem&gt; poems = poemRepository.findByLanguage(language);
        <span class="hljs-keyword">final</span> String[] poemsArray = poems.stream()
            .map(p -&gt; p.getText())
            .collect(Collectors.toList())
            .toArray(<span class="hljs-keyword">new</span> String[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">return</span> poemsArray;
    }
}
</code></pre>
<p>Finally, the team implements the <a target="_blank" href="https://github.com/bertilmuth/poem-springboot/blob/master/src/main/java/poem/springboot/Application.java">Application</a> class that sets up an example repository and plugs the adapters into the ports.</p>
<p>And that's it. The switch to Spring is complete.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>There are many ways to implement a hexagonal architecture. I showed  you a straightforward approach that provides an easy to use, command  driven API for the hexagon. It reduces the number of interfaces you need  to implement. And it leads to a pure domain model.</p>
<p>If you want to get more information on the topic, read <a target="_blank" href="http://archive.is/5j2NI">Alistair Cockburn’s original article on the subject</a>.</p>
<p>The example in this article is inspired by a three part series of <a target="_blank" href="https://www.youtube.com/playlist?list=PLGl1Jc8ErU1w27y8-7Gdcloy1tHO7NriL">talks</a> by Alistair Cockburn on the subject.</p>
<p><em>Last updated on 30 July 2021.__. If you want to keep up with what I’m doing or drop me a note, follow me on</em> <a target="_blank" href="https://dev.to/bertilmuth"><em>dev.to</em></a><em>,</em> <a target="_blank" href="https://www.linkedin.com/in/bertilmuth/"><em>LinkedIn</em></a> <em>or</em> <a target="_blank" href="https://twitter.com/BertilMuth"><em>Twitter</em></a><em>. Or visit my</em> <a target="_blank" href="https://github.com/bertilmuth/requirementsascode"><em>GitHub project</em></a><em>. To learn about agile software development,</em> <a target="_blank" href="https://skl.sh/2Cq497P"><em>visit my online course</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
