<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Romain Rochegude</title>
    <description>The latest articles on DEV Community by Romain Rochegude (@roroche).</description>
    <link>https://dev.to/roroche</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4218860%2F6d604ab3-f74d-43f8-98de-3b586c51edc3.png</url>
      <title>DEV Community: Romain Rochegude</title>
      <link>https://dev.to/roroche</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roroche"/>
    <language>en</language>
    <item>
      <title>Rethinking Hexagonal Architecture with Elegant Objects</title>
      <dc:creator>Romain Rochegude</dc:creator>
      <pubDate>Sat, 31 Oct 2026 10:50:03 +0000</pubDate>
      <link>https://dev.to/roroche/rethinking-hexagonal-architecture-with-elegant-objects-278j</link>
      <guid>https://dev.to/roroche/rethinking-hexagonal-architecture-with-elegant-objects-278j</guid>
      <description>&lt;p&gt;Hexagonal architecture provides a useful foundation: business behavior should remain independent of the technologies used to expose it or persist its state. Ports define the interactions; adapters connect them to the outside world.&lt;/p&gt;

&lt;p&gt;Yet this separation does not, by itself, tell us where behavior belongs.&lt;/p&gt;

&lt;p&gt;One common implementation keeps the dependency directions of hexagonal architecture but puts most business decisions in use cases and services. Domain objects then act mainly as data structures, while other objects interpret and change their state. That is a valid design in some contexts, but it is not the only way to apply hexagonal architecture.&lt;/p&gt;

&lt;p&gt;Reading &lt;a href="https://www.elegantobjects.org/" rel="noopener noreferrer"&gt;Elegant Objects&lt;/a&gt; challenged how I approached this design. Its emphasis on encapsulation, composition, and small objects led me to ask: &lt;strong&gt;what changes when domain objects own more of the behavior that depends on their state?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I will explore that question through an e-commerce cart. The examples are deliberately small: supporting types and repetitive delegation methods are omitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the responsibility
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The usual suspects
&lt;/h3&gt;

&lt;p&gt;A common implementation of “add an item to the cart” might distribute the work across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AddItemToCartUseCase&lt;/code&gt;, a port, and its implementation;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CartController&lt;/code&gt;, a primary adapter that receives &lt;code&gt;AddItemRequestDto&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CartRepository&lt;/code&gt;, a secondary port, and &lt;code&gt;JpaCartRepository&lt;/code&gt;, its adapter;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CartEntity&lt;/code&gt;, the JPA model, and &lt;code&gt;Cart&lt;/code&gt;, the domain model, connected by &lt;code&gt;CartMapper&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CartDto&lt;/code&gt;, which carries the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can involve around ten types for one operation. Each can have a legitimate purpose. A persistence model may protect the domain from ORM constraints. A DTO may define a stable API contract. An application service may coordinate objects and transactions.&lt;/p&gt;

&lt;p&gt;The design becomes harder to follow when those types divide one concept's behavior among them. For example, &lt;code&gt;Cart&lt;/code&gt; may expose data while a use case decides what that data means and how it can change.&lt;/p&gt;

&lt;p&gt;Hexagonal architecture does not require this arrangement. It permits a rich domain model. The question is whether our implementation makes that model visible.&lt;/p&gt;

&lt;p&gt;Before adding another layer, I want to establish what a cart is responsible for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the cart an explicit contract
&lt;/h2&gt;

&lt;p&gt;For this example, a cart knows its contents and total. It can accept or remove an item and initiate checkout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Items&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Items&lt;/span&gt; &lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;total&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The examples below omit repetitive methods such as &lt;code&gt;remove()&lt;/code&gt; and &lt;code&gt;checkout()&lt;/code&gt;, along with error handling and transaction boundaries.&lt;/p&gt;

&lt;p&gt;The caller asks the cart to perform an operation. It does not retrieve a mutable list, modify it, and ask a repository to save the result. This gives the cart a boundary for rules about its contents.&lt;/p&gt;

&lt;p&gt;The distinction goes beyond method names. Renaming &lt;code&gt;getTotal()&lt;/code&gt; to &lt;code&gt;total()&lt;/code&gt; changes little if the calculation still lives elsewhere. What matters is that the cart owns the meaning of its total and hides how it is obtained.&lt;/p&gt;

&lt;p&gt;The contract exposes the values needed by callers through &lt;code&gt;sku()&lt;/code&gt; and &lt;code&gt;price()&lt;/code&gt;, while keeping cart operations behind its own boundary.&lt;/p&gt;

&lt;p&gt;Each item represents one cart entry. Quantities, discounts, and price changes belong in explicit concepts such as a &lt;code&gt;CartLine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;checkout()&lt;/code&gt; makes the cart responsible for coordinating payment and order creation. An application service can coordinate the wider workflow, while the cart owns rules about its contents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep persistence behind the contract
&lt;/h2&gt;

&lt;p&gt;Once the behavior is defined, we can choose how to implement it. Here, &lt;code&gt;PgCart&lt;/code&gt; represents a user's cart stored in PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PgCart&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataSource&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PgCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataSource&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JdbcSession&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO cart_item (user_id, sku) VALUES (?, ?)"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Outcome&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VOID&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Other Cart methods omitted.&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor captures the dependencies and the cart's identity. Database work happens when an operation is invoked.&lt;/p&gt;

&lt;p&gt;This implementation removes the need for a separate persistence entity and its mapper in this example. &lt;code&gt;PgCart&lt;/code&gt; encapsulates access to persistent state and exposes it through the &lt;code&gt;Cart&lt;/code&gt; contract. It is not a persistence-ignorant domain object: it combines domain behavior with database access, and a call such as &lt;code&gt;items()&lt;/code&gt; may involve database queries.&lt;/p&gt;

&lt;p&gt;One important distinction: its fields are final, but the cart's observable state can change. Adding an item changes the database, and a later call may return different contents. Fixed references do not make a persistent object an immutable value, nor do they guarantee thread safety.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Cart&lt;/code&gt; contract knows nothing about SQL or &lt;code&gt;DataSource&lt;/code&gt;, and &lt;code&gt;PgCart&lt;/code&gt; depends on that contract. &lt;code&gt;Cart&lt;/code&gt; is a domain abstraction, not an application port. &lt;code&gt;PgCart&lt;/code&gt; is both a secondary adapter and a domain object: the dependency points inward, but domain behavior and persistence are deliberately combined.&lt;/p&gt;

&lt;p&gt;The hexagon remains at the system boundary: &lt;code&gt;TkCart&lt;/code&gt; translates HTTP requests, and &lt;code&gt;PgCart&lt;/code&gt; connects the cart to PostgreSQL. Inside that boundary, this design keeps the domain abstraction and persistence behavior together rather than introducing a separate persistence port.&lt;/p&gt;

&lt;p&gt;The roles in this example are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TkCart&lt;/code&gt; is the primary HTTP adapter.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JsonCart&lt;/code&gt; defines the JSON representation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Cart&lt;/code&gt;, &lt;code&gt;NonEmptyCart&lt;/code&gt;, and &lt;code&gt;LoggedCart&lt;/code&gt; form the domain contract and its decorators.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PgCart&lt;/code&gt; is both the secondary PostgreSQL adapter and a domain object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FakeCart&lt;/code&gt; is a test implementation of &lt;code&gt;Cart&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Compose behavior around the object
&lt;/h2&gt;

&lt;p&gt;With a behavioral interface in place, additional responsibilities can be expressed through composition.&lt;/p&gt;

&lt;p&gt;Suppose checkout must reject an empty cart. A decorator can make that rule explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NonEmptyCart&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;NonEmptyCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The cart is empty"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Other Cart methods delegate to origin.&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then assemble the cart where the application's dependencies are wired:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoggedCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NonEmptyCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PgCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The composition shows which responsibilities apply: persistent storage, an empty-cart check, and logging. Each wrapper depends on &lt;code&gt;Cart&lt;/code&gt;, so its behavior can be tested with a small fake implementation such as &lt;code&gt;FakeCart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Order matters: logging surrounds validation and records rejected checkout attempts as well as successful ones.&lt;/p&gt;

&lt;p&gt;The empty-cart check and checkout are separate calls, so another request could modify the cart between them. &lt;code&gt;PgCart&lt;/code&gt; must enforce the invariant atomically with the relevant database changes.&lt;/p&gt;

&lt;p&gt;A real checkout must also account for payment failures and retries. A database transaction cannot atomically include an external payment provider. Moving behavior into objects makes these responsibilities easier to locate, but does not remove them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give HTTP representation its own responsibility
&lt;/h2&gt;

&lt;p&gt;The next boundary is the API response. The domain should remain independent of HTTP and JSON libraries.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/yegor256/takes#rsjson" rel="noopener noreferrer"&gt;Takes framework's &lt;code&gt;RsJSON&lt;/code&gt; example&lt;/a&gt; provides a useful starting point: a response wraps an object capable of producing JSON. I use that approach through a dedicated representation object, keeping framework dependencies outside the &lt;code&gt;Cart&lt;/code&gt; contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JsonItem&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RsJSON&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Source&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;JsonItem&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="nf"&gt;toJSON&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createObjectBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sku"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"price"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JsonCart&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RsJSON&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Source&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;JsonCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="nf"&gt;toJSON&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;JsonArrayBuilder&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createArrayBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonItem&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toJSON&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createObjectBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"total"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;JsonCart&lt;/code&gt; owns the response structure. It wraps a cart instead of copying its values into a second model before serialization. Formatting money as a string keeps this example short; a public API may need separate amount and currency fields.&lt;/p&gt;

&lt;p&gt;The HTTP entry point wires the same decorators around the persistent cart before returning the representation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TkCart&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Take&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataSource&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TkCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataSource&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;act&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RsJSON&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JsonCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LoggedCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NonEmptyCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PgCart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                    &lt;span class="o"&gt;),&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;
                &lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TkCart&lt;/code&gt; receives the shared database connection and logger when it is constructed. For each request, it extracts the user's id, builds the same &lt;code&gt;LoggedCart(NonEmptyCart(PgCart(...)))&lt;/code&gt; composition, and wraps it in the JSON representation. The HTTP adapter connects request identity, cart behavior, and response without making the domain contract depend on HTTP.&lt;/p&gt;

&lt;p&gt;The response would look something like this, with illustrative prices for IT books about Elegant Objects and hexagonal architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"69.98 EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ELEGANT-OBJECTS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"34.99 EUR"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HEXAGONAL-ARCHITECTURE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"34.99 EUR"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the API representation a clear place to evolve. A different response format can be introduced without changing &lt;code&gt;Cart&lt;/code&gt;. The mapping responsibility still exists; it now belongs to an object that produces the representation directly.&lt;/p&gt;

&lt;p&gt;An alternative is to pass the result of &lt;code&gt;Json.createObjectBuilder()&lt;/code&gt; to a &lt;code&gt;mapToJson&lt;/code&gt; method on &lt;code&gt;Item&lt;/code&gt; and &lt;code&gt;Cart&lt;/code&gt;. Each object would then choose which parts of its state to expose, at the cost of coupling business interfaces to the JSON API. Here, &lt;code&gt;JsonItem&lt;/code&gt; and &lt;code&gt;JsonCart&lt;/code&gt; keep that representation responsibility outside the domain contract.&lt;/p&gt;

&lt;p&gt;A DTO remains useful when an explicit snapshot is required. In this example, &lt;code&gt;items()&lt;/code&gt; and &lt;code&gt;total()&lt;/code&gt; are separate reads, so concurrent changes could produce an inconsistent response. A DTO alone does not solve that problem; the implementation needs a consistent read strategy or snapshot if the API promises that both describe the same instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use names to communicate responsibility
&lt;/h2&gt;

&lt;p&gt;Some naming rules of thumb I now follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefer names that say what an object is.&lt;/strong&gt; Names ending in &lt;code&gt;-er&lt;/code&gt;, such as &lt;code&gt;Controller&lt;/code&gt;, &lt;code&gt;Mapper&lt;/code&gt;, &lt;code&gt;Manager&lt;/code&gt;, or &lt;code&gt;Handler&lt;/code&gt;, describe what an object does to others. They point toward procedures organized around someone else's data. Prefer the underlying concept: &lt;code&gt;Payment&lt;/code&gt;, &lt;code&gt;Outbox&lt;/code&gt;, or &lt;code&gt;Cart&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use technology prefixes to distinguish implementations.&lt;/strong&gt; &lt;code&gt;PgCart&lt;/code&gt; identifies the PostgreSQL implementation; &lt;code&gt;TkCart&lt;/code&gt; and &lt;code&gt;RsJSON&lt;/code&gt; identify framework-facing objects. &lt;code&gt;StripePayment&lt;/code&gt; is clearer than &lt;code&gt;CardPayment&lt;/code&gt; when naming an implementation tied to a payment provider. In a codebase using Takes, &lt;code&gt;Fk&lt;/code&gt; already means Fork (&lt;code&gt;FkRegex&lt;/code&gt;, &lt;code&gt;FkTypes&lt;/code&gt;), while Takes calls its test doubles &lt;code&gt;RqFake&lt;/code&gt; and &lt;code&gt;RsFake&lt;/code&gt;; &lt;code&gt;FakeCart&lt;/code&gt; avoids giving one prefix two meanings. Prefixes help only when the team shares their meaning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use adjectives to describe decorators.&lt;/strong&gt; &lt;code&gt;NonEmptyCart&lt;/code&gt; and &lt;code&gt;LoggedCart&lt;/code&gt; make added behavior visible; &lt;code&gt;CachedItems&lt;/code&gt; would communicate the same idea for a cached collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The other names in this example follow the same intent: &lt;code&gt;Cart&lt;/code&gt; defines the business contract, &lt;code&gt;JsonCart&lt;/code&gt; identifies an API representation, and &lt;code&gt;FakeCart&lt;/code&gt; provides a test implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluate the trade-offs
&lt;/h2&gt;

&lt;p&gt;The main benefit of this experiment is a more direct relationship between a business concept and its behavior. We can find cart operations through &lt;code&gt;Cart&lt;/code&gt;, persistence through &lt;code&gt;PgCart&lt;/code&gt;, and response formatting through &lt;code&gt;JsonCart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This does not guarantee fewer classes. Decorators and representation objects can increase their number. The useful measure is how much of the system a developer must understand to change a rule safely.&lt;/p&gt;

&lt;p&gt;Several constraints deserve attention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data access:&lt;/strong&gt; small objects can hide repeated queries. Measure query behavior and choose batching or a deliberate loading strategy. Caching requires a clear lifetime and invalidation policy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; composition does not define transaction boundaries. Business invariants must hold under concurrent access and partial failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability:&lt;/strong&gt; &lt;code&gt;FakeCart&lt;/code&gt; lets tests exercise decorators such as &lt;code&gt;NonEmptyCart&lt;/code&gt; without infrastructure. &lt;code&gt;PgCart&lt;/code&gt; owns database-backed behavior, including &lt;code&gt;total()&lt;/code&gt;, so tests of those rules require PostgreSQL. This design makes some behavior easy to test in isolation; it does not make the persistent cart infrastructure-free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework integration:&lt;/strong&gt; frameworks built around mutable entities, reflection, and generated mappings may make this approach costly to introduce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation:&lt;/strong&gt; many small objects can reduce local complexity while making the overall behavior harder to follow. Shared conventions and selective decomposition matter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an existing application, start with one bounded behavior and assess the result: can the team locate the rule more easily, test the right boundary, and understand the dependencies? Those answers provide better guidance than adherence to a naming rule or a target class count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bring the question back to your code
&lt;/h2&gt;

&lt;p&gt;Choose a business concept in your application: a cart, an invoice, or an order. Follow one operation from the entry point to persistence and identify where each decision is made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the object own its rules, or must its callers understand its internal state to apply them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a decision depends on the object's own state, moving it behind the object's contract can strengthen encapsulation. When an operation coordinates several objects or external systems, an application service may still be the clearest place for that coordination.&lt;/p&gt;

&lt;p&gt;Hexagonal architecture helps us control the boundary between the application and its environment. Elegant Objects encourages us to examine the responsibilities within that boundary. Together, they offer a useful way to question familiar structures and make design choices explicit.&lt;/p&gt;

&lt;p&gt;The goal is a system whose behavior can be located, understood, and changed with confidence.&lt;/p&gt;

</description>
      <category>java</category>
      <category>architecture</category>
      <category>hexagonalarchitecture</category>
      <category>elegantobjects</category>
    </item>
  </channel>
</rss>
