<?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: Horse Patterns</title>
    <description>The latest articles on DEV Community by Horse Patterns (@horse_patterns).</description>
    <link>https://dev.to/horse_patterns</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3120288%2F616d7e47-a602-422e-8968-1acb8643ec13.jpg</url>
      <title>DEV Community: Horse Patterns</title>
      <link>https://dev.to/horse_patterns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/horse_patterns"/>
    <language>en</language>
    <item>
      <title>Clean Architecture: The Four Concentric Circles Explained</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Wed, 17 Sep 2025 19:36:38 +0000</pubDate>
      <link>https://dev.to/horse_patterns/clean-architecture-the-four-concentric-circles-explained-26g0</link>
      <guid>https://dev.to/horse_patterns/clean-architecture-the-four-concentric-circles-explained-26g0</guid>
      <description>&lt;p&gt;In modern software development, complexity grows quickly. Without the right structure, codebases can become fragile, difficult to test, and costly to maintain. &lt;strong&gt;Clean Architecture&lt;/strong&gt; offers a clear design philosophy that addresses these challenges head-on by keeping your core business logic pure, independent from frameworks, databases, and other external tools. As a result, your application remains maintainable, testable, and adaptable, even as technology evolves.&lt;/p&gt;

&lt;p&gt;This article examines the principles of &lt;strong&gt;Clean Architecture&lt;/strong&gt;, its structural organization, and a practical example of its implementation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Clean Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Formal Definition:&lt;/strong&gt;&lt;br&gt;
Clean Architecture is a software design philosophy that organizes an application into distinct, independent layers. Its main goal is to &lt;strong&gt;separate core business rules from implementation details&lt;/strong&gt; such as frameworks, databases, or user interfaces.&lt;/p&gt;

&lt;p&gt;By applying this separation, you can:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace a database without touching your business logic.
&lt;/li&gt;
&lt;li&gt;Swap out a web framework without rewriting the entire system.
&lt;/li&gt;
&lt;li&gt;Test core rules without relying on slow, brittle external systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Structure of Clean Architecture
&lt;/h2&gt;

&lt;p&gt;Visualize Clean Architecture as &lt;strong&gt;four concentric circles&lt;/strong&gt;, each representing a layer with a specific responsibility: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entities – Enterprise Business Rules&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contain core domain models and rules.
&lt;/li&gt;
&lt;li&gt;Independent of frameworks, databases, or libraries.
&lt;/li&gt;
&lt;li&gt;Designed to be stable and reusable across multiple applications. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases – Application Business Rules&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define how the application responds to inputs.
&lt;/li&gt;
&lt;li&gt;Coordinate between entities and business rules.
&lt;/li&gt;
&lt;li&gt;Remain unaware of the web, UI, or database details.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Interface Adapters&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contain controllers, presenters, gateways, and mappers.
&lt;/li&gt;
&lt;li&gt;Adapt data between external systems and internal layers.
&lt;/li&gt;
&lt;li&gt;Translate input/output into forms that the core application understands.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Frameworks &amp;amp; Drivers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Include databases, web frameworks, file systems, or other external tools.
&lt;/li&gt;
&lt;li&gt;Considered “details” rather than the essence of the application.
&lt;/li&gt;
&lt;li&gt;Can be swapped without affecting the business logic.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Importance of Clean Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Each layer focuses on a single purpose, making the system easier to maintain and extend.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Business rules can be tested without databases or frameworks.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Change frameworks, databases, or UI layers without touching the core logic.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Supports growth and integration without sacrificing structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Example
&lt;/h2&gt;

&lt;p&gt;The following example demonstrates how Clean Architecture principles can be applied in practice, illustrating the separation of concerns across its distinct concentric circles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Object - Entities
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.thedevhorse.cleanarchitecture.domain&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;class&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;athleteId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Athlete&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;athleteId&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;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;athleteId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;athleteId&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&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;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;setCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&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;static&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="nf"&gt;create&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;String&lt;/span&gt; &lt;span class="n"&gt;athleteId&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;String&lt;/span&gt; &lt;span class="n"&gt;name&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;int&lt;/span&gt; &lt;span class="n"&gt;age&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;new&lt;/span&gt; &lt;span class="nf"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&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;Represents the core business entity. Independent from infrastructure, frameworks, or databases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.thedevhorse.cleanarchitecture.usecase&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;class&lt;/span&gt; &lt;span class="nc"&gt;AthleteUseCaseImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;AthleteInputPort&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;AthleteDaoOutputPort&lt;/span&gt; &lt;span class="n"&gt;athleteDaoOutputPort&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;AthleteUseCaseImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AthleteDaoOutputPort&lt;/span&gt; &lt;span class="n"&gt;athleteDaoOutputPort&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;athleteDaoOutputPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;athleteDaoOutputPort&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;Athlete&lt;/span&gt; &lt;span class="nf"&gt;getAthlete&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;String&lt;/span&gt; &lt;span class="n"&gt;athleteId&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="n"&gt;athleteDaoOutputPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAthleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteId&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;createAthlete&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;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;athleteDaoOutputPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athlete&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;updateAthlete&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;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;athleteDaoOutputPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athlete&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;Implements application-specific business rules, orchestrating actions between ports and entities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case - Input Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.thedevhorse.cleanarchitecture.usecase.port.in&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;AthleteInputPort&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="nf"&gt;getAthlete&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;athleteId&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;createAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&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;updateAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&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;Defines the contract for use cases, shielding the implementation from external dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case - Output Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.thedevhorse.cleanarchitecture.usecase.port.out&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;AthleteDaoOutputPort&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="nf"&gt;getAthleteById&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;athleteId&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;createAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&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;updateAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&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;Specifies how the use case interacts with persistence layers without knowing the actual database details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interface Adapters – Controller
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.thedevhorse.cleanarchitecture.infra.controller&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/athletes"&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;class&lt;/span&gt; &lt;span class="nc"&gt;AthleteController&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;AthleteInputPort&lt;/span&gt; &lt;span class="n"&gt;athleteInputPort&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;AthleteController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AthleteInputPort&lt;/span&gt; &lt;span class="n"&gt;athleteInputPort&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;athleteInputPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;athleteInputPort&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{athleteId}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;AthleteResponse&lt;/span&gt; &lt;span class="nf"&gt;getAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;athleteId&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="nf"&gt;mapToAthleteResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;athleteInputPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteId&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="nd"&gt;@PostMapping&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;createAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;AthleteRequest&lt;/span&gt; &lt;span class="n"&gt;athleteRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;athleteInputPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;mapToAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteRequest&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="nd"&gt;@PutMapping&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;updateAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt;  &lt;span class="nc"&gt;AthleteRequest&lt;/span&gt; &lt;span class="n"&gt;athleteRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;athleteInputPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;mapToAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteRequest&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;Acts as the bridge between HTTP requests and the use case, adapting incoming and outgoing data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frameworks &amp;amp; Drivers – DB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.thedevhorse.cleanarchitecture.infra.repository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AthleteDaoImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;AthleteDaoOutputPort&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;AthleteRepository&lt;/span&gt; &lt;span class="n"&gt;athleteRepository&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;AthleteDaoImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AthleteRepository&lt;/span&gt; &lt;span class="n"&gt;athleteRepository&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;athleteRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;athleteRepository&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;Athlete&lt;/span&gt; &lt;span class="nf"&gt;getAthleteById&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;String&lt;/span&gt; &lt;span class="n"&gt;athleteId&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="nf"&gt;mapToAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findEntityById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteId&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;createAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;athleteRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapToAthleteEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athlete&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;updateAthlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;AthleteEntity&lt;/span&gt; &lt;span class="n"&gt;athleteEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findEntityById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;athleteId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;athleteEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;athleteEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="n"&gt;athleteRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteEntity&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;Implements persistence operations using a specific framework and database, hidden behind the output port interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By applying &lt;strong&gt;Clean Architecture&lt;/strong&gt;, you build applications where:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core business logic is isolated&lt;/strong&gt; from technical details.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsibilities are clearly separated&lt;/strong&gt; across layers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frameworks and tools are replaceable&lt;/strong&gt; without rewriting the business core.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This results in &lt;strong&gt;flexible, maintainable, and testable systems&lt;/strong&gt; — ready to evolve as your requirements change.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=4hVbaHeaJy4" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=4hVbaHeaJy4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn't come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;strong&gt;&lt;em&gt;"The only way to go fast, is to go well."&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" rel="noopener noreferrer"&gt;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>softwaredevelopment</category>
      <category>programming</category>
      <category>development</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Microservices: Beyond the Word</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Tue, 12 Aug 2025 18:33:45 +0000</pubDate>
      <link>https://dev.to/horse_patterns/microservices-beyond-the-word-4lhn</link>
      <guid>https://dev.to/horse_patterns/microservices-beyond-the-word-4lhn</guid>
      <description>&lt;p&gt;The concept of microservices has gained popularity as a modern and flexible way to develop systems. However, as Martin Fowler said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The term 'microservice' is a label, not a description."&lt;br&gt;
- Martin Fowler`&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The trouble starts when the prefix "micro" is taken literally, leading teams to create overly fragmented, complex, and hard-to-maintain services. More important than size is the proper design of boundaries and service autonomy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the Label
&lt;/h2&gt;

&lt;p&gt;When we talk about microservices, the first image that comes to mind is of small, distributed chunks of code. But delivering real value requires careful design and execution.&lt;/p&gt;

&lt;p&gt;If poorly applied, microservices can turn into a &lt;strong&gt;distributed monolith&lt;/strong&gt;  - with tight coupling, hard-to-manage dependencies, and complexity that grows exponentially.&lt;/p&gt;

&lt;h3&gt;
  
  
  To avoid this, some key principles should guide the design:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Clear boundaries:&lt;/strong&gt; each service should represent a specific domain or subdomain, avoiding overlapping responsibilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Well-defined context:&lt;/strong&gt; draw from &lt;em&gt;Domain-Driven Design&lt;/em&gt; to ensure business rules are isolated and consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;True independence:&lt;/strong&gt; each service should be developed, tested, deployed, and scaled independently, without being blocked by other teams or systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-team ownership:&lt;/strong&gt; each service should be managed by only one team, ensuring clear responsibility and faster decision-making.&lt;/p&gt;

&lt;p&gt;Following these principles, microservices stop being just "small bits of code" and become &lt;strong&gt;truly independent components&lt;/strong&gt;, owned and managed by a &lt;strong&gt;single, cross-functional team&lt;/strong&gt;, making them easier to maintain, scale, and evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The "micro" in microservices is not about size, but about focus and independence. By thinking in terms of clear boundaries, well-defined context, and autonomy, we create systems that deliver more value to the domain and its users - without falling into the trap of excessive fragmentation.&lt;/p&gt;

&lt;p&gt;More than following a trend, it's about applying a design that enables sustainable growth, simplified maintenance, and rapid evolution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Follow the YouTube channel for more tips about software architecture:&lt;br&gt;
🟥▶️&lt;a href="https://www.youtube.com/@HorsePatterns" rel="noopener noreferrer"&gt;https://www.youtube.com/@HorsePatterns&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Architectural Trade-offs: Making the Right Decision for Your Context</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Tue, 05 Aug 2025 22:15:22 +0000</pubDate>
      <link>https://dev.to/horse_patterns/architectural-trade-offs-making-the-right-decision-for-your-context-3e7i</link>
      <guid>https://dev.to/horse_patterns/architectural-trade-offs-making-the-right-decision-for-your-context-3e7i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Everything in software architecture is a trade-off.”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
— &lt;em&gt;First Law of Software Architecture&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When it comes to software architecture, this quote couldn't be more accurate. Every architectural choice we make comes with its own set of benefits and compromises. Navigating these trade-offs thoughtfully is what separates a good system from a great one, or from one that fails to meet real-world demands.&lt;/p&gt;

&lt;p&gt;Every architecture decision must be made with context in mind. That means carefully evaluating a variety of factors before landing on the right design for your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Considerations When Choosing an Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Functional Requirements:&lt;/strong&gt; The system must deliver the necessary features and behavior. Your architecture should support and enhance core functionality, not obstruct it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure Limitations and Cost:&lt;/strong&gt; Cloud costs, data center constraints, or third-party licensing directly impact what is feasible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Delivery Timeline:&lt;/strong&gt;  The architecture must support delivery within the expected time frame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Expertise of the Team:&lt;/strong&gt; The development team has the skills and experience needed to support the chosen architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team Organization:&lt;/strong&gt; The architecture should align with how your teams are structured and how they communicate. A good match between system design and team boundaries accelerates progress and reduces friction.&lt;/p&gt;

&lt;p&gt;These are just some of the elements that influence architecture decisions. The right choice depends heavily on your unique situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Fit for Your Architecture
&lt;/h2&gt;

&lt;p&gt;There’s no one-size-fits-all. The right architecture depends on the team, the goals, and the constraints.&lt;/p&gt;

&lt;p&gt;Whether you choose a Monolithic Architecture&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl094zyyjci3l3o1d7xgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl094zyyjci3l3o1d7xgx.png" alt=" " width="260" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A single codebase with a unified deployment. Simple to start with, but harder to scale and maintain as complexity grows.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Microservices Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6lqqlvcpn8dv2tl3p4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6lqqlvcpn8dv2tl3p4x.png" alt=" " width="800" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multiple independent services with clear responsibilities. Offers flexibility and scalability, but adds operational overhead.&lt;/p&gt;

&lt;p&gt;Or a &lt;strong&gt;Shared-Kernel Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhiq7kbodendolahnn3ud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhiq7kbodendolahnn3ud.png" alt=" " width="603" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A compromise between independence and shared responsibility. Encourages collaboration and reuse, but requires tight coordination.&lt;/p&gt;

&lt;p&gt;Take the time to weigh the trade-offs and choose what best fits your team, context, and goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Software architecture is not about finding the perfect solution. It's about making the right trade-offs for your specific situation. Each decision must be grounded in a clear understanding of your requirements, limitations, and team structure.&lt;/p&gt;

&lt;p&gt;By weighing the trade-offs of each architecture style and aligning them with your goals, you create a foundation for long-term success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;Follow the YouTube channel for more tips about software architecture:&lt;br&gt;
🟥▶️&lt;a href="https://www.youtube.com/@HorsePatterns" rel="noopener noreferrer"&gt;https://www.youtube.com/@HorsePatterns&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>architecture</category>
      <category>microservices</category>
      <category>programming</category>
    </item>
    <item>
      <title>Domain Event Pattern for Decoupled Architectures</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Tue, 22 Jul 2025 22:32:54 +0000</pubDate>
      <link>https://dev.to/horse_patterns/domain-event-pattern-for-decoupled-architectures-50mf</link>
      <guid>https://dev.to/horse_patterns/domain-event-pattern-for-decoupled-architectures-50mf</guid>
      <description>&lt;p&gt;In modern applications, different parts of a system often need to react to changes without being tightly coupled. For example, when a user registers or an order is placed, several components might need to send notifications, update analytics, or trigger workflows.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Domain Event Pattern&lt;/strong&gt; provides a clean solution to this problem by modeling significant business events as immutable facts. It allows systems to communicate through events in a decoupled way, making them more modular, scalable, and easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Domain Event Pattern?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Domain Event Pattern&lt;/strong&gt;, a key concept in &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt;, captures significant changes within your business domain as immutable events. A domain event represents a fact that has already occurred - such as &lt;strong&gt;&lt;em&gt;"Order Created"&lt;/em&gt;&lt;/strong&gt; or &lt;em&gt;&lt;strong&gt;"User Registered"&lt;/strong&gt;&lt;/em&gt; - and includes details like timestamps, unique IDs, and domain data. Because these events are immutable, they preserve the integrity of the system's history, making it easier to debug and audit.&lt;/p&gt;

&lt;p&gt;The key advantage of this pattern is decoupling. When a domain event is raised, the producing code does not need to know who will handle it or how. This separation allows different parts of your application to work independently. It is especially powerful in complex systems or microservice architectures, where services can react to events without direct dependencies on each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Components of the Domain Event Pattern
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Domain Event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Domain Event&lt;/strong&gt; represents something that has happened in the past and describes a change in the state of the domain. It must include the date of occurrence, the ID of the aggregate, and a message for subscribers. A domain event must be immutable, and its name should be written in the past to indicate that it has already occurred.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Publisher&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Event Publisher&lt;/strong&gt; is responsible for broadcasting domain events. It decouples the producer, such as an order service, from consumers who might act on those events. These events can be published either synchronously or asynchronously, depending on your requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Consumers / Handlers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Consumers or Handlers&lt;/strong&gt; are components that react to domain events. For example, when an order is placed, one consumer might send a confirmation email, while another triggers a system notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Messaging System (Optional)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In distributed systems, a &lt;strong&gt;Messaging System&lt;/strong&gt; can be introduced to carry domain events across service boundaries. Tools like Kafka or RabbitMQ are commonly used to facilitate cross-service communication, allowing different microservices to subscribe to and react to events independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Domain Events
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Loose Coupling:&lt;/strong&gt; Producers and consumers do not need to know about each other, which reduces dependencies and makes your system easier to maintain and evolve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; Asynchronous event handling enables the application to execute multiple operations concurrently, optimizing system resource utilization and improving both throughput and responsiveness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensibility:&lt;/strong&gt; Adding new event handlers becomes straightforward without altering existing code that produces events. This allows your system to adapt quickly to new requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traceability:&lt;/strong&gt; Domain events leave a clear audit trail in your system. This means you always know what happened and when, making debugging and auditing much simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Example
&lt;/h2&gt;

&lt;p&gt;Now, a simple example of the Domain Event Pattern shows how all the pieces fit together to build a clean and decoupled system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OrderMessage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll start with a class called &lt;strong&gt;&lt;em&gt;OrderMessage&lt;/em&gt;&lt;/strong&gt;. It's a container for order information, like ID, current status, and other relevant details. It also makes it easy to convert an &lt;strong&gt;&lt;em&gt;Order&lt;/em&gt;&lt;/strong&gt; object into an &lt;strong&gt;&lt;em&gt;OrderMessage&lt;/em&gt;&lt;/strong&gt;, allowing us to share order changes with other parts of the system.&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;OrderMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;status&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderMessage&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&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;new&lt;/span&gt; &lt;span class="nf"&gt;OrderMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&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;strong&gt;OrderCreated&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next up is &lt;strong&gt;&lt;em&gt;OrderCreated&lt;/em&gt;&lt;/strong&gt;, which represents our domain event. Imagine it as a notification about the newly created order so other components in the system can react appropriately. This class keeps track of a unique event ID, the order details using &lt;strong&gt;&lt;em&gt;OrderMessage&lt;/em&gt;&lt;/strong&gt;, and a timestamp indicating when the event occurred. A factory method is also provided to make the creation of these events straightforward and clean.&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;OrderCreated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OrderMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="n"&gt;occurred&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;DomainEvent&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderCreated&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                      &lt;span class="nc"&gt;OrderMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                      &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="n"&gt;occurred&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;new&lt;/span&gt; &lt;span class="nf"&gt;OrderCreated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;occurred&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;strong&gt;Order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let's take a look at the core domain object: the &lt;strong&gt;Order&lt;/strong&gt;. It acts as an aggregate root that encapsulates business logic and key information. Any change to its status may represent a domain event, which must be propagated to other bounded contexts and external systems.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;status&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;orderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderId&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;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;status&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;static&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;orderId&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;Status&lt;/span&gt; &lt;span class="n"&gt;status&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;new&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;status&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;strong&gt;OrderServiceImpl&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we have the &lt;strong&gt;&lt;em&gt;OrderServiceImpl&lt;/em&gt;&lt;/strong&gt; class, which handles the creation of orders in the system. This is where the Domain Event Pattern demonstrates its effectiveness.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;createOrder&lt;/em&gt;&lt;/strong&gt; method, when a new order is created, we immediately generate an &lt;strong&gt;&lt;em&gt;OrderCreated&lt;/em&gt;&lt;/strong&gt; event populated with the order's details and the current timestamp. Instead of acting directly on this event (such as sending notifications or updating analytics), we delegate it to a &lt;strong&gt;&lt;em&gt;MessagePublisher&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This approach clearly illustrates the advantages of decoupling. The service responsible for creating the order does not need to know what actions will follow. It simply raises the event and proceeds, leaving it to other components of the system to determine how to handle it.&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;class&lt;/span&gt; &lt;span class="nc"&gt;OrderServiceImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;OrderService&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;MessagePublisher&lt;/span&gt; &lt;span class="n"&gt;messagePublisher&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;OrderServiceImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MessagePublisher&lt;/span&gt; &lt;span class="n"&gt;messagePublisher&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;messagePublisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messagePublisher&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;createOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;OrderCreated&lt;/span&gt; &lt;span class="n"&gt;orderCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderCreated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="nc"&gt;OrderMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;messagePublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publisher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderCreated&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Domain Event Pattern&lt;/strong&gt; provides a clean and efficient way to design systems that are extensible, scalable, and easy to maintain. It's especially powerful in complex domains or microservice architectures where changes in one part of the system need to trigger actions in another.&lt;/p&gt;

&lt;p&gt;By capturing business events as immutable facts, you enable a richer, more auditable, and more modular architecture. This pattern helps you build software that's not only robust today but also ready to evolve with future requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=fbk2xL3vgNI&amp;amp;t" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=fbk2xL3vgNI&amp;amp;t&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn't come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;strong&gt;&lt;em&gt;"The only way to go fast, is to go well."&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Evans, E. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003.&lt;/li&gt;
&lt;li&gt;Vernon, V. Implementing Domain-Driven Design. Addison-Wesley, 2013&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>eventdriven</category>
      <category>softwaredevelopment</category>
      <category>ddd</category>
      <category>java</category>
    </item>
    <item>
      <title>Domain Model Patterns: Bringing Your Domain to Life</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Thu, 03 Jul 2025 21:15:00 +0000</pubDate>
      <link>https://dev.to/horse_patterns/domain-model-patterns-bringing-your-domain-to-life-2hlp</link>
      <guid>https://dev.to/horse_patterns/domain-model-patterns-bringing-your-domain-to-life-2hlp</guid>
      <description>&lt;p&gt;In complex software systems, how you structure your domain logic can make the difference between chaos and clarity. Domain Model Patterns provide a powerful way to organize business logic using objects that mirror the real-world rules and concepts of your application. These patterns help developers build expressive, maintainable, and adaptable systems that evolve gracefully with changing business needs.&lt;/p&gt;

&lt;p&gt;Let's explore the key building blocks of the Domain Model and how they work together to bring your domain to life.&lt;/p&gt;

&lt;h2&gt;
  
  
  Value Objects: Small, Immutable and Value Equality
&lt;/h2&gt;

&lt;p&gt;Value Objects are characterized solely by their attributes. They are &lt;strong&gt;immutable&lt;/strong&gt;, meaning their internal state cannot be changed once created. Unlike entities, they have no identity. Two &lt;strong&gt;Value Objects with the same data are considered equal&lt;/strong&gt;, regardless of where or how they are used. This makes them ideal for modeling concepts like measurements, addresses or contact information, where the focus is on the values themselves rather than on individual instances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example – Contact Value Object&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's an implementation of a &lt;em&gt;Contact&lt;/em&gt; Value Object. It includes validation for the email format and encapsulates contact details in an immutable, value-based structure:&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;class&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ValueObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mobileNumber&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Contact&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;email&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;mobileNumber&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;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&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;mobileNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mobileNumber&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;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&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;static&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="nf"&gt;of&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;String&lt;/span&gt; &lt;span class="n"&gt;email&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;String&lt;/span&gt; &lt;span class="n"&gt;mobileNumber&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;String&lt;/span&gt; &lt;span class="n"&gt;address&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;new&lt;/span&gt; &lt;span class="nf"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;mobileNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;address&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setEmail&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;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"the email cannot be null."&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;regexPattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@"&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"&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="n"&gt;isMatches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regexPattern&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;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email address."&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&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;This approach ensures that each &lt;em&gt;Contact&lt;/em&gt; object is always valid and consistent. Since it's immutable, any change (like updating the email) results in the creation of a new instance, preserving data integrity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entities: Unique Identity
&lt;/h2&gt;

&lt;p&gt;Unlike Value Objects, Entities are defined by a &lt;strong&gt;unique identity&lt;/strong&gt; that remains constant throughout their lifecycle. Their internal state may evolve, but their identity persists. Entities are used when it's important to track an object as a distinct individual over time, regardless of how its attributes change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example – PersonalData Entity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's an implementation of a &lt;em&gt;PersonalData&lt;/em&gt; Entity. It uses a &lt;em&gt;citizenId&lt;/em&gt; as a unique identifier and includes mutable fields such as name, age, and contact information:&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;class&lt;/span&gt; &lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;PersonalData&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;citizenId&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;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                         &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                         &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;citizenId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setContact&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contact&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;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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;static&lt;/span&gt; &lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="nf"&gt;of&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;String&lt;/span&gt; &lt;span class="n"&gt;citizenId&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;String&lt;/span&gt; &lt;span class="n"&gt;name&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;int&lt;/span&gt; &lt;span class="n"&gt;age&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;Contact&lt;/span&gt; &lt;span class="n"&gt;contact&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;new&lt;/span&gt; &lt;span class="nf"&gt;PersonalData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;citizenId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;contact&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateEmail&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;String&lt;/span&gt; &lt;span class="n"&gt;newEmail&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;contact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mobileNumber&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&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;This example illustrates how Entities encapsulate both data and behavior. The &lt;em&gt;PersonalData&lt;/em&gt; class ensures that business rules, such as input validation or managing state changes, are enforced through well-defined methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggregates: Enforcing Consistency Boundaries
&lt;/h2&gt;

&lt;p&gt;An Aggregate is a group of related Entities and Value Objects treated as a single unit for data changes. It establishes a boundary that encapsulates business rules and enforces consistency.&lt;/p&gt;

&lt;p&gt;At the heart of every Aggregate is the &lt;strong&gt;Aggregate Root, the only entry point&lt;/strong&gt; for making changes within the boundary. This Root controls access and ensures the integrity of all enclosed components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example – Athlete Aggregate Root or Root Entity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Athlete&lt;/em&gt; class serves as the Aggregate Root. It encapsulates related information such as &lt;em&gt;PersonalData&lt;/em&gt; and &lt;em&gt;Category&lt;/em&gt;, and provides methods to enforce business rules like updating contact info or assigning a category based on age:&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;class&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractAggregateRoot&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Athlete&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;athleteId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setPersonalData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&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;static&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="nf"&gt;create&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;String&lt;/span&gt; &lt;span class="n"&gt;athleteId&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;PersonalData&lt;/span&gt; &lt;span class="n"&gt;personalData&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;new&lt;/span&gt; &lt;span class="nf"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;athleteId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;personalData&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateEmail&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;String&lt;/span&gt; &lt;span class="n"&gt;newMobileNumber&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;personalData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newMobileNumber&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setPersonalData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="n"&gt;personalData&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;personalData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"The personalData cannot be null."&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;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;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Category not found for the age: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;age&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;This example highlights how the &lt;em&gt;Athlete&lt;/em&gt; class acts as a gateway to the aggregate. All updates, such as changing an email address or determining the athlete's category based on age, are managed through this root. This ensures that the internal state of the aggregate remains valid and consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supporting Patterns: Repositories, Domain Services and Factories
&lt;/h2&gt;

&lt;p&gt;Beyond the core domain model, supporting patterns help organize responsibilities, reduce complexity and maintain a clear separation of concerns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repositories&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Repositories provide controlled access to Aggregates. They handle storing, retrieving and searching for domain objects without leaking persistence logic into the domain model itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain Services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Domain Service handles business operations that don't naturally belong to any single Entity or Value Object. It is stateless and often coordinates activities across multiple Aggregates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Factories&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Factories encapsulate the creation logic of complex objects, ensuring that Entities and Aggregates are always instantiated in a valid, consistent state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Applying &lt;strong&gt;Domain Model Patterns&lt;/strong&gt; is more than an architectural choice - it's a mindset that brings clarity, robustness, and agility to your software. By distinguishing between Value Objects and Entities, organizing related data into Aggregates, and supporting them with Repositories, Domain Services, and Factories, you can design systems that reflect the true nature of your business domain.&lt;/p&gt;

&lt;p&gt;These patterns not only help you write cleaner code but also ensure that your software remains flexible and adaptable as it grows. Embrace these principles, and you'll be well on your way to building software that stands the test of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=cb_h_LHMgjw&amp;amp;t" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=cb_h_LHMgjw&amp;amp;t&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn't come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;strong&gt;&lt;em&gt;“The only way to go fast, is to go well.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Evans, E. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vernon, V. Implementing Domain-Driven Design. Addison-Wesley, 2013.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ddd</category>
      <category>programming</category>
      <category>development</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Understanding Domain-Driven Design (DDD)</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Sun, 15 Jun 2025 16:40:22 +0000</pubDate>
      <link>https://dev.to/horse_patterns/understanding-domain-driven-design-ddd-2h6o</link>
      <guid>https://dev.to/horse_patterns/understanding-domain-driven-design-ddd-2h6o</guid>
      <description>&lt;p&gt;Domain-Driven Design (DDD) is a powerful approach to designing and building complex software systems. Introduced by &lt;strong&gt;Eric Evans&lt;/strong&gt; in his influential book &lt;strong&gt;Domain-Driven Design: Tackling Complexity in the Heart of Software (2003)&lt;/strong&gt;, DDD provides both strategic principles and tactical patterns that help teams create scalable, maintainable, and business-aligned software.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Domain-Driven Design?
&lt;/h2&gt;

&lt;p&gt;DDD encourages teams to focus on the business domain, the core area of knowledge and activity around which the business revolves. Rather than viewing software as just code or infrastructure, DDD promotes building software that mirrors and models real-world business processes and logic.&lt;/p&gt;

&lt;p&gt;By understanding the domain deeply, developers can craft systems that are not only functional but also aligned with the needs and goals of the business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Domain-Driven Design Is a Game Changer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Solves Complex Business Problems&lt;/strong&gt;&lt;br&gt;
DDD shines in areas with intricate business logic, such as finance, healthcare, and logistics, because it models these complexities directly in the software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improves Communication&lt;/strong&gt;&lt;br&gt;
By using a Ubiquitous Language, DDD fosters a shared vocabulary among developers, stakeholders, and domain experts, reducing miscommunication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enhances Maintainability and Scalability&lt;/strong&gt;&lt;br&gt;
DDD’s modular approach, especially through Bounded Contexts, helps teams build systems that are easier to evolve and extend over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supports Modern Architectures&lt;/strong&gt;&lt;br&gt;
DDD aligns well with Microservices and Event-Driven Systems, promoting loose coupling, autonomy and flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aligns Code with Business Needs&lt;/strong&gt;&lt;br&gt;
By constantly refining the Domain Model, teams ensure that the software adapts as business requirements change, avoiding costly rewrites.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pillars of Domain-Driven Design
&lt;/h2&gt;

&lt;p&gt;To apply Domain-Driven Design effectively, it's important to understand its foundational concepts. These core pillars provide the structure and mindset necessary to model complex domains with clarity and precision. Let's examine each pillar to understand how it supports the design of effective and maintainable software systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Ubiquitous Language&lt;/strong&gt;&lt;br&gt;
A Ubiquitous Language is a shared, domain-specific vocabulary used consistently by all team members.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Applied in code, documentation, and discussions.&lt;/li&gt;
&lt;li&gt;Developed collaboratively with domain experts.&lt;/li&gt;
&lt;li&gt;Ensures clarity and avoids ambiguity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
In an e-commerce platform, instead of generically saying Order, the team uses specific terms like Purchase Order, Shipment, and Payment Transaction to reflect the business accurately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates miscommunication.&lt;/li&gt;
&lt;li&gt;Improves understanding.&lt;/li&gt;
&lt;li&gt;Enhances consistency across the codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Bounded Context&lt;/strong&gt;&lt;br&gt;
A Bounded Context defines a logical boundary within which a particular domain model is valid. It isolates different interpretations and usages of the same term in different parts of the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example (E-Commerce Platform Subdomains):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvug5taq41jkurjodmsc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvug5taq41jkurjodmsc8.png" alt="E-Commerce Platform Subdomains" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer (Supporting Subdomain):&lt;/strong&gt; Manages customer profiles and preferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Order (Core Subdomain):&lt;/strong&gt; Manages order creation, payment and shipping, which are central to the business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory (Generic Subdomain):&lt;/strong&gt; Handles stock and logistics using standard industry practices.&lt;/p&gt;

&lt;p&gt;Each of these subdomains operates in its own Bounded Context, allowing teams to model them independently and clearly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Encourages modular design.&lt;/li&gt;
&lt;li&gt; Prevents model conflicts.&lt;/li&gt;
&lt;li&gt; Enables team autonomy and parallel development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Context Map&lt;/strong&gt;&lt;br&gt;
A Context Map describes how multiple Bounded Contexts relate and interact with each other in a system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Relationship Types:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared Kernel:&lt;/strong&gt; A small shared model used across contexts (requires collaboration).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partnership:&lt;/strong&gt; Tight coordination and mutual dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer–Supplier:&lt;/strong&gt; The upstream context provides services or data (the Supplier), while the downstream context (the Customer) consumes it and adapts accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anti-Corruption Layer (ACL):&lt;/strong&gt; A translation layer that protects domain purity when integrating external or upstream models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example (Context Map in Action):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzwza7pb4n093spb06fi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzwza7pb4n093spb06fi.png" alt="Context Map in Action" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared Kernel:&lt;/strong&gt; Customer and Order contexts share a small, common data model (e.g., customer IDs).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anti-Corruption Layer (ACL):&lt;/strong&gt; Order communicates with Inventory through an ACL to protect its domain model from upstream changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Supports safe integrations.&lt;/li&gt;
&lt;li&gt; Maintains context independence.&lt;/li&gt;
&lt;li&gt; Reduces coupling between domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Tactical Patterns in DDD
&lt;/h2&gt;

&lt;p&gt;Beyond its core principles, Domain-Driven Design includes powerful tactical patterns that guide the implementation of domain logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aggregate Roots&lt;/strong&gt; define transactional boundaries and ensure consistency across related entities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entities and Value Objects&lt;/strong&gt;  model real-world concepts - Entities have distinct identities, while Value Objects are immutable and defined by their properties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain Events&lt;/strong&gt; represent meaningful domain changes, enabling decoupled communication and supporting event-driven designs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repositories&lt;/strong&gt; abstract data access, allowing developers to interact with aggregates using domain language instead of persistence logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain Services&lt;/strong&gt; encapsulate business operations that don't naturally belong to any single entity or value object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Factories&lt;/strong&gt; manage the creation of complex objects or aggregates, ensuring they're instantiated in a valid and consistent state.&lt;/p&gt;

&lt;p&gt;Together, these patterns create a clean, expressive, and maintainable domain model that supports business goals and system scalability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Domain-Driven Design is more than a methodology, it's a mindset focused on modeling software that mirrors the business it serves.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ubiquitous Language&lt;/strong&gt; fosters communication and shared understanding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded Contexts&lt;/strong&gt; maintain clarity and modularity in complex systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Mapping&lt;/strong&gt; defines how parts of the system collaborate effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tactical Patterns&lt;/strong&gt; provide the tools to implement business logic cleanly and effectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By adopting DDD, software teams can build systems that are technically sound, aligned with business strategy, and ready to evolve alongside the organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=tLaw8kvm_xA&amp;amp;t" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=tLaw8kvm_xA&amp;amp;t&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn't come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;strong&gt;&lt;em&gt;“The only way to go fast, is to go well.”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evans, E.&lt;/strong&gt; Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vernon, V&lt;/strong&gt;. Implementing Domain-Driven Design. Addison-Wesley, 2013.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>developer</category>
      <category>ddd</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Domain Validation with the Notification Pattern</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Wed, 28 May 2025 20:09:13 +0000</pubDate>
      <link>https://dev.to/horse_patterns/domain-validation-with-the-notification-pattern-99o</link>
      <guid>https://dev.to/horse_patterns/domain-validation-with-the-notification-pattern-99o</guid>
      <description>&lt;p&gt;In software engineering, validation is an essential step, especially when handling user input or ensuring compliance with business rules. Although it’s common to use exceptions to signal errors, this approach can be ineffective for expected issues, such as empty fields or invalid formats.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Notification Pattern&lt;/strong&gt; addresses this problem by collecting all errors in a notification object, allowing them to be handled in a structured way and presented to the user clearly and efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Notification Pattern?
&lt;/h2&gt;

&lt;p&gt;The Notification Pattern is a design strategy that collects validation errors rather than throwing exceptions immediately. It allows your application to gather multiple issues in one go and report them collectively, which is especially useful when validating complex domain objects.&lt;/p&gt;

&lt;p&gt;This approach provides users with comprehensive feedback and developers with cleaner, more maintainable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use the Notification Pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prevents Overuse of Exceptions:&lt;/strong&gt; Exceptions should signal unexpected errors. Validation errors, however, are expected and should be handled differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better User Feedback:&lt;/strong&gt; Multiple validation errors can be collected and displayed together, preventing a frustrating “whack-a-mole” experience for users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decoupling Logic:&lt;/strong&gt; By using the Notification Pattern, validation logic is separated from the flow control of the program, making it easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Notification Pattern Works
&lt;/h2&gt;

&lt;p&gt;The Notification Pattern introduces a structured flow to handling validation in your domain models. Rather than interrupting execution with exceptions, it captures and organizes all issues for smarter downstream handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notification Object&lt;/strong&gt;&lt;br&gt;
A centralized container that holds a list of validation errors. It acts as an error aggregator across multiple fields or objects within the domain logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validation Phase&lt;/strong&gt;&lt;br&gt;
Instead of immediately throwing exceptions when a validation rule fails, the rule appends an error message to the notification object. This continues for all validations, allowing the system to collect every issue in one pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;br&gt;
Once all validations are complete, the application checks the notification object. If errors are present, a domain-specific exception (like &lt;em&gt;DomainViolationException&lt;/em&gt;) can be thrown, or the errors can be handled gracefully.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sample Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure of the Notification Pattern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Notification Pattern is composed of three main parts that work together to validate domain models without immediately throwing exceptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validation Interface&lt;/strong&gt;&lt;br&gt;
A common contract that defines how individual validation rules behave.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom Exception&lt;/strong&gt;&lt;br&gt;
An exception that wraps all collected violations into a single throwable unit, allowing for comprehensive error reporting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Notification Object&lt;/strong&gt;&lt;br&gt;
An accumulator that gathers all validation errors for a given domain object.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Validation Interface&lt;/strong&gt;&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;DomainValidation&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getErrorMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&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;abstract&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&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;strong&gt;Custom Exception&lt;/strong&gt;&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;class&lt;/span&gt; &lt;span class="nc"&gt;DomainViolationException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Violation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;violations&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;DomainViolationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt; &lt;span class="n"&gt;claz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Violation of Domain rules in object %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;claz&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSimpleName&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;violations&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;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&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;addViolation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Violation&lt;/span&gt; &lt;span class="n"&gt;violation&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;violations&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="n"&gt;violation&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="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Violation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getViolations&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="n"&gt;violations&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;strong&gt;Notification Object&lt;/strong&gt;&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;class&lt;/span&gt; &lt;span class="nc"&gt;DomainExceptionNotification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;DomainViolationException&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;DomainExceptionNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;claz&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;exception&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;DomainViolationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claz&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;validateAndSet&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;objName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DomainValidation&lt;/span&gt; &lt;span class="n"&gt;violation&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="n"&gt;violation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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;exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addViolation&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;DomainViolationException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Violation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getErrorMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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="n"&gt;obj&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validateDomainObject&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;exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getViolations&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&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;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exception&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;enum&lt;/span&gt; &lt;span class="nc"&gt;ValidationEnum&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;DomainValidation&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;NULL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"field cannot be null"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&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="nf"&gt;nonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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="no"&gt;BLANK&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"field cannot be blank"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&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="nf"&gt;nonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&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="nc"&gt;ValidationEnum&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;errorMessage&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;;&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;String&lt;/span&gt; &lt;span class="n"&gt;errorMessage&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getErrorMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&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="n"&gt;errorMessage&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="kd"&gt;abstract&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&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;h2&gt;
  
  
  Applying to domain objects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Athlete&lt;/em&gt; Domain Object&lt;/strong&gt;&lt;br&gt;
Validates required fields (&lt;em&gt;personalData&lt;/em&gt; and &lt;em&gt;category&lt;/em&gt;) before creation.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Athlete&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;athleteId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="nc"&gt;PersonalData&lt;/span&gt; &lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;DomainExceptionNotification&lt;/span&gt; &lt;span class="n"&gt;notification&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;DomainExceptionNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&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;personalData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateAndSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"personalData"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DomainExceptionNotification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ValidationEnum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NULL&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="n"&gt;nonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;personalData&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;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateAndSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findCategoryFromAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;personalData&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="nc"&gt;DomainExceptionNotification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ValidationEnum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NULL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateDomainObject&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;strong&gt;&lt;em&gt;Contact&lt;/em&gt; Domain Object&lt;/strong&gt;&lt;br&gt;
Validates the &lt;em&gt;email&lt;/em&gt; field using a custom rule.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mobileNumber&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Contact&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;email&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;mobileNumber&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;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DomainExceptionNotification&lt;/span&gt; &lt;span class="n"&gt;notification&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;DomainExceptionNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateAndSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&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;EmailValidation&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;mobileNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mobileNumber&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;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateDomainObject&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;static&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="nf"&gt;of&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;String&lt;/span&gt; &lt;span class="n"&gt;email&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;String&lt;/span&gt; &lt;span class="n"&gt;mobileNumber&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;String&lt;/span&gt; &lt;span class="n"&gt;address&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;new&lt;/span&gt; &lt;span class="nf"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;mobileNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;address&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Notification Pattern&lt;/strong&gt; is a powerful technique for handling validation in domain-driven applications. It provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cleaner code by avoiding excessive exception handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved feedback by reporting all errors at once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better maintainability through separation of validation and flow control.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By structuring your domain logic around notifications instead of exceptions, your applications become more robust, more user-friendly, and easier to evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=pxpN4WJtrjU" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=pxpN4WJtrjU&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn’t come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;em&gt;&lt;strong&gt;“The only way to go fast, is to go well.”&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fowler, M. (n.d.). Notification. MartinFowler.com. &lt;a href="https://martinfowler.com/eaaDev/Notification.html" rel="noopener noreferrer"&gt;https://martinfowler.com/eaaDev/Notification.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BurnedPanic. notification-pattern. GitHub, &lt;a href="https://github.com/BurnedPanic/notification-pattern" rel="noopener noreferrer"&gt;https://github.com/BurnedPanic/notification-pattern&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Simplifying Business Rules with the Specification Pattern</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Sun, 04 May 2025 17:43:18 +0000</pubDate>
      <link>https://dev.to/horse_patterns/simplifying-business-rules-with-the-specification-pattern-4o4o</link>
      <guid>https://dev.to/horse_patterns/simplifying-business-rules-with-the-specification-pattern-4o4o</guid>
      <description>&lt;p&gt;The Specification Pattern is a design pattern that allows you to encapsulate validation criteria in separate objects, making the code more modular and flexible. Instead of writing complex conditional logic directly in the main code, this responsibility is delegated to specification objects. This makes the code easier to understand, maintain, and extend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Specification Pattern?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Specification Pattern&lt;/strong&gt; is a way to encapsulate business rules into reusable, composable objects.&lt;/p&gt;

&lt;p&gt;Instead of cluttering your domain objects or services with multiple conditions, you define clear and testable specifications that determine whether an object meets certain criteria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In simple terms:&lt;/strong&gt;&lt;br&gt;
🔹 It separates business logic from domain models.&lt;br&gt;
🔹 It allows flexible and reusable rule composition (AND, OR, NOT conditions).&lt;br&gt;
🔹 It makes code more readable, testable, and maintainable.&lt;/p&gt;
&lt;h2&gt;
  
  
  When to Use the Specification Pattern
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your business logic is complex and frequently changes.&lt;/li&gt;
&lt;li&gt;You need to reuse rules across multiple parts of the application.&lt;/li&gt;
&lt;li&gt;You want to keep domain models lightweight and focused.&lt;/li&gt;
&lt;li&gt;You are following &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt; principle&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Applying the Specification Pattern
&lt;/h2&gt;

&lt;p&gt;Let’s consider an example: a &lt;strong&gt;weightlifting competition system&lt;/strong&gt; where athletes qualify for specific events based on their performance in lifts like the &lt;strong&gt;Snatch and Clean &amp;amp; Jerk.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A bad approach would be stuffing complex if-else conditions directly into domain models. This makes the code harder to read and reduces flexibility when business rules change.&lt;/p&gt;

&lt;p&gt;The Specification Pattern offers a cleaner solution: it extracts these conditions into self-contained objects that can be combined dynamically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Weightlifting Competition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Specification objects contain individual validation rules. In the given code, there are classes such as:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Specification Objects&lt;/u&gt;&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;class&lt;/span&gt; &lt;span class="nc"&gt;CleanAndJerkOlympicsSpecification&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CompositeSpecification&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="no"&gt;MINIMUM_WEIGHT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;200.0&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;BiPredicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toPredicate&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="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snatch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cleanAndJerk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cleanAndJerk&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MINIMUM_WEIGHT&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;A similar specification would be created for the Snatch.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Composing Specifications&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Specifications can be combined using logical operators like AND and OR. For example:&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;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setEligibleForOlympics&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;snatchWeight&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;cleanAndJerkWeight&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;eligibleForOlympics&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;CleanAndJerkOlympicsSpecification&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&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;SnatchOlympicsSpecification&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toPredicate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snatchWeight&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cleanAndJerkWeight&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;Each specification is transformed into a &lt;strong&gt;Predicate&lt;/strong&gt;, which is a condition that can be tested. The &lt;em&gt;toPredicate()&lt;/em&gt; method converts each specification into a boolean condition that can be tested using the athlete’s snatch and clean &amp;amp; jerk weights.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Example: Email Validation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Specifications can also validate other types of data, such as email addresses:&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;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSpecification&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;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;boolean&lt;/span&gt; &lt;span class="nf"&gt;isSatisfiedBy&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;email&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;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^(.+)@(\\S+)$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&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;The code below shows how to use &lt;code&gt;EmailSpecification&lt;/code&gt; to validate an athlete’s email.&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;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAthleteEmail&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;athleteEmail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isValidEmail&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;EmailSpecification&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isSatisfiedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;athleteEmail&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="n"&gt;isValidEmail&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;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email."&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;athleteEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;athleteEmail&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Specification Pattern&lt;/strong&gt; allows you to encapsulate business rules into separate, composable components, making the code modular, reusable, and easier to maintain. It is particularly useful when there are multiple complex conditions that need to be evaluated against objects, such as checking an athlete’s eligibility for competitions or validating input like email addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=ByERVyGQN_A" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=ByERVyGQN_A&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn’t come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;strong&gt;&lt;em&gt;“The only way to go fast, is to go well.”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Specification Pattern — Martin Fowler’s Catalog of Patterns of Enterprise Application Architecture: &lt;a href="https://martinfowler.com/apsupp/spec.pdf" rel="noopener noreferrer"&gt;https://martinfowler.com/apsupp/spec.pdf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Embracing Rich Domain Objects: A Practical Guide</title>
      <dc:creator>Horse Patterns</dc:creator>
      <pubDate>Sat, 03 May 2025 19:47:50 +0000</pubDate>
      <link>https://dev.to/horse_patterns/embracing-rich-domain-objects-a-practical-guide-13ia</link>
      <guid>https://dev.to/horse_patterns/embracing-rich-domain-objects-a-practical-guide-13ia</guid>
      <description>&lt;p&gt;In the domain of software design, the way data is modeled significantly impacts the clarity, robustness, and scalability of an application. As systems evolve and become increasingly complex, the need for clear domain boundaries and well-encapsulated behavior becomes essential.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Rich Domain Objects (RDO)&lt;/strong&gt; offer a compelling solution. RDOs advocate for encapsulating both &lt;strong&gt;state and behavior&lt;/strong&gt; within domain entities, thereby promoting a more cohesive and maintainable architecture.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the concept of Rich Domain Objects, their benefits, and how they can be effectively implemented in Java using a practical, real-world example. By the end, you will gain a deeper understanding of this approach and walk away with testable, production-ready code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Rich Domain Objects
&lt;/h2&gt;

&lt;p&gt;Rich Domain Objects are rooted in the principles of &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt;. They encourage developers to model software entities based not solely on data structure, but also on domain specific responsibilities and behavior.&lt;/p&gt;

&lt;p&gt;Unlike anemic domain models, which serve merely as data containers, Rich Domain Objects (RDOs) encapsulate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State&lt;/strong&gt; (data)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business logic&lt;/strong&gt; (behavior)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation rules&lt;/strong&gt; (ensure data integrity and enforce domain constraints)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This encapsulation ensures that domain rules are enforced consistently and that object behavior remains predictable and coherent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Rich Domain Objects
&lt;/h2&gt;

&lt;p&gt;Adopting Rich Domain Objects offers several architectural and development benefits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encapsulation of Business Logic:&lt;/strong&gt; By keeping business rules within the domain model, logic stays close to the data it governs, reducing scattering across services or controllers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improved Domain Consistency:&lt;/strong&gt; Validation and rule enforcement are centralized, preventing invalid states from emerging during runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-Validation:&lt;/strong&gt; Objects verify their own validity upon state changes, resulting in more reliable systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expressive APIs:&lt;/strong&gt; Methods such as &lt;em&gt;changeCategory()&lt;/em&gt; communicate domain intent more clearly than traditional setters like &lt;em&gt;setCategory()&lt;/em&gt; and &lt;em&gt;setAge()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business-Aligned Code:&lt;/strong&gt; The object model naturally mirrors domain language, improving communication between technical and non-technical stakeholders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Example: Modeling an Athlete Domain
&lt;/h2&gt;

&lt;p&gt;To demonstrate the utility of RDOs, let us consider an &lt;em&gt;Athlete&lt;/em&gt; class responsible for managing personal data and categorizing athletes based on their age.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Athlete&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;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Athlete&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;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&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;static&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="nf"&gt;create&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;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;new&lt;/span&gt; &lt;span class="nf"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;name&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="n"&gt;name&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="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;age&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="n"&gt;age&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="nc"&gt;Category&lt;/span&gt; &lt;span class="nf"&gt;category&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="n"&gt;category&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;changeCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Age must be a positive number."&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;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;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;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Category not found for the age: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;age&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;This implementation ensures that age and category are always valid and correctly synchronized, reducing the likelihood of inconsistent object states.&lt;/p&gt;

&lt;p&gt;The following &lt;em&gt;Category&lt;/em&gt; enum provides a clear and self-contained definition of age-based classifications:&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;enum&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;JUNIOR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;ELITE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;MASTER&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&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;int&lt;/span&gt; &lt;span class="n"&gt;minAge&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;int&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minAge&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxAge&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;minAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minAge&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;maxAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maxAge&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="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;minAge&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="n"&gt;minAge&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="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;maxAge&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="n"&gt;maxAge&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;Whenever an athlete’s age is set or updated, the appropriate category is automatically applied in accordance with the business rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing the Reliability of Rich Domain Objects&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the key benefits of Rich Domain Objects is that they are inherently easier to test. Because the business logic is embedded within the domain itself, unit tests become more focused and reliable.&lt;/p&gt;

&lt;p&gt;Below is a JUnit test suite that verifies the expected behavior of the &lt;em&gt;Athlete&lt;/em&gt; class:&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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;givenValidInputs_whenCreateAthleteIsCalled_thenAthleteIsReturned&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Athlete&lt;/span&gt; &lt;span class="n"&gt;athlete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Horse Power"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MASTER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;givenInvalidAge_whenCreateAthleteIsCalled_thenIllegalArgumentExceptionThrown&lt;/span&gt;&lt;span class="o"&gt;()&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;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Horse"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Category not found for the age: 5"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;givenNegativeAge_whenCreateAthleteIsCalled_thenExceptionThrown&lt;/span&gt;&lt;span class="o"&gt;()&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;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Athlete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Horse"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Age must be a positive number."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tests demonstrate how domain rules are strictly enforced, ensuring the creation of only valid, well-formed objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Rich Domain Objects represent a fundamental shift toward more robust, behavior-oriented domain modeling. They enable developers to create systems that are not only easier to maintain but also more aligned with real-world business processes.&lt;/p&gt;

&lt;p&gt;By embedding business logic within domain entities, developers can build applications that are resilient, expressive, and aligned with stakeholder language. This approach also facilitates better testing, clearer APIs, and a reduction in bugs related to invalid object states.&lt;/p&gt;

&lt;p&gt;Before creating your next domain model, consider the following question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Should this object merely store data, or should it also know how to manage and validate that data?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In many cases, the latter leads to a more accurate and effective design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;For a step-by-step video walkthrough of this example and further explanation of the pattern in action, watch the full tutorial:&lt;/p&gt;

&lt;p&gt;🟥▶️&lt;a href="https://www.youtube.com/watch?v=uJ8BLJqaE8Q" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=uJ8BLJqaE8Q&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, real speed doesn’t come from rushing. It comes from doing things right. As Robert C. Martin said, &lt;strong&gt;&lt;em&gt;“The only way to go fast, is to go well.”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>java</category>
      <category>cleancode</category>
      <category>development</category>
    </item>
  </channel>
</rss>
