<?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: Jérôme Navez</title>
    <description>The latest articles on DEV Community by Jérôme Navez (@jnavez).</description>
    <link>https://dev.to/jnavez</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%2F1064310%2Faeb2ce74-e2ec-420d-bbde-676f7eeec6ad.jpeg</url>
      <title>DEV Community: Jérôme Navez</title>
      <link>https://dev.to/jnavez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jnavez"/>
    <language>en</language>
    <item>
      <title>Spring Boot - Implementing a Distributed Task Scheduler (without queue)</title>
      <dc:creator>Jérôme Navez</dc:creator>
      <pubDate>Sat, 14 Oct 2023 15:13:35 +0000</pubDate>
      <link>https://dev.to/jnavez/spring-boot-implementing-a-distributed-task-scheduler-without-queue-2m13</link>
      <guid>https://dev.to/jnavez/spring-boot-implementing-a-distributed-task-scheduler-without-queue-2m13</guid>
      <description>&lt;p&gt;When developing a service, one of the challenges you could face is the need to execute tasks that run &lt;strong&gt;automatically and periodically&lt;/strong&gt;.&lt;br&gt;
Those tasks could contain &lt;strong&gt;undefined and/or unpredictable amounts of work and load&lt;/strong&gt;, so the need to have a &lt;strong&gt;scalable architecture&lt;/strong&gt; is strong.&lt;/p&gt;

&lt;p&gt;Limiting the implementation of this challenge to simple &lt;code&gt;@Scheduled&lt;/code&gt; annotations is not enough to support horizontal scaling. Indeed, for each instance sharing the same launch configuration, a &lt;code&gt;@Scheduled&lt;/code&gt; method will trigger its task as many times as there are instances running.&lt;/p&gt;

&lt;p&gt;To solve that, the classic approach would be to use a &lt;strong&gt;queue&lt;/strong&gt;. One task scheduler sends the tasks info in a queue and multiple consumers poll this queue to execute the tasks. Depending on the load, more or fewer consumer instances are launched.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--10aRlys1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q747820jp3vd53wu1rrt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--10aRlys1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q747820jp3vd53wu1rrt.png" alt="Producer-Consumers Architecture" width="709" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this architecture is certainly a good choice, it may not fit your technical constraints and needs. This also obliges you to bring the concept of messaging to your project.&lt;/p&gt;

&lt;p&gt;In this article, we will see how we can rethink this challenge by avoiding relying on a Publisher-Consumers architecture but by &lt;strong&gt;relying on a relational database&lt;/strong&gt; and its locking mechanisms.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's rethink the problem
&lt;/h2&gt;

&lt;p&gt;What are we trying to achieve here?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We want:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to make sure that the tasks run once;&lt;/li&gt;
&lt;li&gt;to trigger those tasks periodically;&lt;/li&gt;
&lt;li&gt;to distribute the load between consumers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how we can achieve that using Spring Boot and a relational database.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Defining the consumer tasks
&lt;/h2&gt;

&lt;p&gt;We first need to define the tasks. We create a service containing one method per identified task.&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;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@EnableScheduling&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;TaskScheduler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&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="n"&gt;timeUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&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;scrapSourceWebsite&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&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="n"&gt;timeUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&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;moveDeletedToColdStorage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Other tasks&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that those methods are launched periodically using the &lt;code&gt;@Scheduled&lt;/code&gt; annotation. At each run, the method will check if the task associated with the method can be executed.&lt;/p&gt;

&lt;p&gt;The period can be 30 seconds, 5 minutes, or even a CRON expression. Depending on your business needs.&lt;/p&gt;

&lt;p&gt;We will come back to the implementation of the methods later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Defining the DB entries
&lt;/h2&gt;

&lt;p&gt;Now that we have defined our service tasks, we can start defining our DB table and entries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;task_lock&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;         &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;last_execution&lt;/span&gt;   &lt;span class="nb"&gt;bigint&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;task_lock&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'scrap_website'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;task_lock&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'move_to_cold'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our table is composed of the &lt;strong&gt;task ID&lt;/strong&gt; and the &lt;strong&gt;timestamp&lt;/strong&gt; of the last execution. This timestamp will be used to evaluate the time since the last execution, thus defining when the task needs to be executed again.&lt;br&gt;
We have &lt;strong&gt;one row per task&lt;/strong&gt;, those are the rows that the instance running the task will lock during the time of execution.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Implementing the locking query
&lt;/h2&gt;

&lt;p&gt;This third step is about being able to effectively lock a row of the table using JPA annotations. &lt;strong&gt;Locking this row will have as effect that any other query will not be able to retrieve it.&lt;/strong&gt; Meaning that the other service instances will not be able to acquire the lock.&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;@Repository&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;TaskLockRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TaskLockEntity&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;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Lock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LockModeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PESSIMISTIC_WRITE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@QueryHints&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;
        &lt;span class="nd"&gt;@QueryHint&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="s"&gt;"jakarta.persistence.lock.timeout"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1000"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;})&lt;/span&gt;
    &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProviderLockEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findByTaskIdAndLastExecutionLessThan&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;taskId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;timestamp&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;We use a &lt;strong&gt;pessimistic write lock&lt;/strong&gt;. When acquired, the lock will stay alive during the time of the transaction. If not acquired, the query will return an empty optional. When trying to acquire a lock, a timeout can be used to define the maximum time a query will wait for a lock to be released (1 second in our example).&lt;/p&gt;

&lt;p&gt;Let's suppose that we have 2 instances running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;scrap_website&lt;/em&gt; is ready to be executed;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;instance 1&lt;/strong&gt; executes the scheduled method &lt;code&gt;scrapSourceWebsite()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance 1&lt;/strong&gt; queries the database and locks &lt;em&gt;"scrap_website"&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;instance 2&lt;/strong&gt; executes the scheduled method &lt;code&gt;scrapSourceWebsite()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance 2&lt;/strong&gt; queries the database and gets no results because it cannot lock the already locked row.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QObuIXp7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zt9smi1xgbn2nvbvjfnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QObuIXp7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zt9smi1xgbn2nvbvjfnu.png" alt="Locking Task Scheduler Example" width="617" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Linking everything together
&lt;/h2&gt;

&lt;p&gt;Now that we have our main components and the repository, it's time to write down our task-scheduling logic. Let's come back to our entry component.&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;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@EnableScheduling&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;TaskScheduler&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;TaskLockRepository&lt;/span&gt; &lt;span class="n"&gt;taskLockRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Other dependencies&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TaskScheduler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TaskLockRepository&lt;/span&gt; &lt;span class="n"&gt;taskLockRepository&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;taskLockRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskLockRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Transactional&lt;/span&gt;
    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&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="n"&gt;timeUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&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;scrapSourceWebsite&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;scheduledRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&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="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HOURS&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 1h&lt;/span&gt;
        &lt;span class="n"&gt;taskLockRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByTaskIdAndLastExecutionLessThan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scrap_website"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scheduledRate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ifPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scrapingTask&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Execute scraping task...&lt;/span&gt;
                &lt;span class="n"&gt;scrapingTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastExecution&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&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;@Transactional&lt;/span&gt;
    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&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="n"&gt;timeUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&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;moveDeletedToColdStorage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;scheduledRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&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="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HOURS&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 6h&lt;/span&gt;
        &lt;span class="n"&gt;taskLockRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByTaskIdAndLastExecutionLessThan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"move_to_cold"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scheduledRate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ifPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moveToCold&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Execute migration of deleted to cold storage...&lt;/span&gt;
                &lt;span class="n"&gt;moveToCold&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastExecution&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&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="c1"&gt;// Other tasks&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As stated above, the query needs to run in a &lt;strong&gt;transaction&lt;/strong&gt;.&lt;br&gt;
You need to define the period associated with the task (&lt;code&gt;scheduledRate&lt;/code&gt;). Respectively 1 and 6 hours in our example. You should use configuration properties if you want to do it the nice way.&lt;/p&gt;

&lt;p&gt;This period and the current timestamp will be used to determine if the task can be picked. If the row is already locked or if the last execution time is too close, the instance will not acquire the lock and the method will end.&lt;/p&gt;

&lt;p&gt;On the other hand, if the lock is acquired, the task is executed and &lt;strong&gt;the timestamp of this execution is saved in the task entity&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  What if the task fails?
&lt;/h2&gt;

&lt;p&gt;The transaction will rollback, nothing will be saved, and &lt;strong&gt;the lock will be released&lt;/strong&gt;. Then another instance will be able to require the lock and retry the task.&lt;/p&gt;

&lt;p&gt;Depending on your business, you may need to disable a task for a given time if a failure occurs. You will need to &lt;strong&gt;handle the error within the transaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example of deactivating a task during 3 hours:&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;TaskScheduler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// dependencies&lt;/span&gt;

    &lt;span class="nd"&gt;@Transactional&lt;/span&gt;
    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&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="n"&gt;timeUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&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;scrapSourceWebsite&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;scheduledRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&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="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HOURS&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;taskLockRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByTaskIdAndLastExecutionLessThanAndDeactivatedUntilLessThan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scrap_website"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scheduledRate&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ifPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scrapingTask&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Execute scraping task...&lt;/span&gt;
                    &lt;span class="n"&gt;scrapingTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastExecution&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Esception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Deactivating for 3 hours&lt;/span&gt;
                    &lt;span class="n"&gt;scrapingTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDeactivatedUntil&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Duration&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="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HOURS&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 3h&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="c1"&gt;// Other tasks&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Side note: When your query method begins to be this long (63 characters 🤯), you should consider rewriting it into JPQL or hiding it behind another method.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if the instance fails and crashes?
&lt;/h2&gt;

&lt;p&gt;This could happen but we are still safe. The worker will stop responding to the database. &lt;strong&gt;The transaction will time out&lt;/strong&gt; in the database and &lt;strong&gt;the lock will be released&lt;/strong&gt;. How much time will it take? It depends on your database configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to monitor the instances load?
&lt;/h2&gt;

&lt;p&gt;Monitoring the instance load is crucial to determine if more or fewer instances need to be launched. One way is to use a &lt;code&gt;ThreadPoolTaskExecutor&lt;/code&gt; to launch the tasks. Then you need to monitor this &lt;code&gt;ThreadPoolTaskExecutor&lt;/code&gt; to get the current number of tasks being executed among all the instances.&lt;/p&gt;

&lt;p&gt;Combined with a good &lt;strong&gt;monitoring system&lt;/strong&gt;, &lt;strong&gt;Micrometer's metrics&lt;/strong&gt; will be your best allies here.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if we need parameters to those tasks?
&lt;/h2&gt;

&lt;p&gt;Indeed, the example is very simple. In real conditions, you could have parameters for those tasks, tasks that need to run the night only, etc. The principle stays the same as long as you lock the row associated with the task.&lt;/p&gt;

&lt;p&gt;Suppose we have a scraping task that needs a website in parameter. We will have this table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Website&lt;/th&gt;
&lt;th&gt;Last execution timestamp&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;amazom.com&lt;/td&gt;
&lt;td&gt;1234&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bol.com&lt;/td&gt;
&lt;td&gt;1267&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The SQL query simply needs to find the first row and order by the timestamp (&lt;em&gt;amazom.com&lt;/em&gt;). Then, the first row being already locked, the next first visible row will be &lt;em&gt;bol.com&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compared to the Producer-Consumer approach
&lt;/h2&gt;

&lt;p&gt;Let's take a step back and compare the Locking Task Scheduling to the classic Producer-Consumer.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Easy to put in place if you already have a SQL database;&lt;/li&gt;
&lt;li&gt;No need to add the messaging concept to the stack;&lt;/li&gt;
&lt;li&gt;Error outcome is easy to handle.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;No task payload, limited number of parameters;&lt;/li&gt;
&lt;li&gt;Require locking capabilities on database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;We saw an approach to implementing a &lt;strong&gt;task-scheduling based on database locks&lt;/strong&gt;. While this technique is not meant to completely replace the producer-consumer method, it proposes &lt;strong&gt;another way of tackling similar challenges&lt;/strong&gt;. This other way of tackling the challenge offers different possibilities and can give you more flexibility on task definition and scheduling.&lt;/p&gt;

&lt;p&gt;Whether you pick Producer-Consumers or Locking Task Scheduler architecture, choosing the right implementation is a risky task. That kind of implementation risk can be mitigated using the &lt;strong&gt;Onion Architecture&lt;/strong&gt;. &lt;a href="https://dev.to/jnavez/make-your-microservices-tastier-by-cooking-them-with-a-sweet-onion-34n2"&gt;In a previous article&lt;/a&gt;, I explained how you can implement this architecture in Spring Boot projects.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A better architecture for your Angular projects</title>
      <dc:creator>Jérôme Navez</dc:creator>
      <pubDate>Sat, 24 Jun 2023 10:56:31 +0000</pubDate>
      <link>https://dev.to/jnavez/a-better-architecture-for-your-angular-projects-4m6l</link>
      <guid>https://dev.to/jnavez/a-better-architecture-for-your-angular-projects-4m6l</guid>
      <description>&lt;p&gt;Conceptually, this architecture could be applied to any frontend framework. Since I have more knowledge of Angular than the other frontend frameworks, I will write Angular examples when necessary.&lt;/p&gt;

&lt;p&gt;If you wish to directly jump to the architecture, click or tap here.&lt;/p&gt;

&lt;p&gt;Before rushing into the technical parts, let's ask ourselves:&lt;/p&gt;

&lt;h2&gt;
  
  
  Why focus on the frontend architecture?
&lt;/h2&gt;

&lt;p&gt;While putting in place a backend architecture is common sense, it may be harder to have a clean architecture on the frontend side.&lt;/p&gt;

&lt;p&gt;For multiple reasons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript Frameworks
&lt;/h3&gt;

&lt;p&gt;Historically, new Javascript framework were popping every day. Being able to master a framework takes time and effort. You need a strong experience to know every capability of a framework and figure out what to do when facing a programmatic challenge.&lt;/p&gt;

&lt;p&gt;Currently, the frontend frameworks seem to be dominated by React, Angular and Vue for some years know. This brings stability. Some pattern and architectural concept are shared among them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend concepts
&lt;/h3&gt;

&lt;p&gt;Frontend uses a lot of concepts that you need to know in order to code your product. Concepts that you don't meet when working on backend.&lt;/p&gt;

&lt;p&gt;Some of the challenges and concepts a frontend developer meet every day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State management to enhance the single source of truth;&lt;/li&gt;
&lt;li&gt;Asynchronous code to not block your UI;&lt;/li&gt;
&lt;li&gt;Combining UX modularity and Code modularity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend vs Frontend architecture
&lt;/h3&gt;

&lt;p&gt;This reason is very influenced by my own perception of IT architecture and what I see in some projects around me.&lt;/p&gt;

&lt;p&gt;Less effort is put into the frontend architectures while more effort is put in the backend architectures.&lt;/p&gt;

&lt;p&gt;Some would say that business logic and security are sensitive backend topics. Those two things must be rock solid. While the frontend is just there to "display things from the backend".&lt;/p&gt;

&lt;p&gt;Indeed, the frontend is nothing without a strong backend. But the reverse is also valuable. Having a strong backend, you don't want a weak frontend full of bugs and hard to maintain to communicate with your backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactoring frontend code is way harder
&lt;/h3&gt;

&lt;p&gt;Disclaimer: I mainly use IntelliJ IDEA.&lt;/p&gt;

&lt;p&gt;Modern IDE has strong refactoring capabilities for Java projects. Renaming filenames and moving classes from package to package is easy.&lt;/p&gt;

&lt;p&gt;I cannot tell the same for Angular projects. Imports unchanged, &lt;code&gt;NgModule&lt;/code&gt; not updated, etc. I always have the feeling that some "smart links" are missing between files.&lt;/p&gt;

&lt;p&gt;By highlighting the separation of concern with a good architecture, the number of those refactoring will decrease and be easier to process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base principles
&lt;/h2&gt;

&lt;p&gt;You may or may not agree with all of those reasons, but you certainly agree on the fact that the frontend architecture deserves time and effort to be well organized.&lt;/p&gt;

&lt;p&gt;The main goal of an architecture is to reduce the coupling between the elements that compose the software. Separation of concern, modularity, abstraction, etc are the main ideas to achieve that.&lt;/p&gt;

&lt;p&gt;Unfortunately, the frontend frameworks suffer from two specific issues that need to be tackled to reach this goal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The business logic tends to be split across multiple components;&lt;/li&gt;
&lt;li&gt;There is a risk of data being contained in multiple places, increasing the chance to use outdated or unsynchronized data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given those objectives and issues, the following architecture put its prioritizes on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stateless components;&lt;/li&gt;
&lt;li&gt;Single source of truth;&lt;/li&gt;
&lt;li&gt;Separation of concern;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The SCA architecture
&lt;/h2&gt;

&lt;p&gt;We need a catchy name. Let's call this architecture the &lt;strong&gt;SCA architecture:&lt;/strong&gt; &lt;em&gt;the Simple and Clean Angular architecture&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's dive into the graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwbu2x1kyi7dtk4lss202.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwbu2x1kyi7dtk4lss202.png" alt="SCA architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The architecture is composed of 4 big parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components&lt;/li&gt;
&lt;li&gt;Domain&lt;/li&gt;
&lt;li&gt;Store&lt;/li&gt;
&lt;li&gt;Infrastructure (most of the time, the clients)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on your project and uses cases, you may also use the local storage or the session storage. Those belong to the infrastructure.&lt;/p&gt;

&lt;p&gt;The store could also be categorized as an infrastructure layer. But since it deserves special attention, let's keep it as a separate part.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain
&lt;/h3&gt;

&lt;p&gt;This is the center of our application. It's composed of services. It can be one simple service or multiple separated services. The domain layer should represent the use-cases, so you need to organize them as logically as possible.&lt;/p&gt;

&lt;p&gt;The domain exposes methods that are actions available for the components. Those actions execute business logic, use the infrastructure, and/or modify the state of the store.&lt;/p&gt;

&lt;p&gt;The domain also exposes selectors that are Observables being selections of the store. &lt;code&gt;RxJs&lt;/code&gt; operators can be applied to this selection, but the final result must always be based on the store value only. They emit each time the selection is modified. Those exposed selectors have a business meaning.&lt;/p&gt;

&lt;p&gt;Selector example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;userAge$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;birthdayDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;birthdayDate&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;birthdayDate&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The domain should be independent of the framework used as much as possible. We should be able to migrate the domain logic from the angular project to any other TypeScript project with very few efforts. Of course, there will always be the &lt;code&gt;@Injectable&lt;/code&gt; and &lt;code&gt;@NgModule&lt;/code&gt; decorators, but you get the idea.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;p&gt;Components are there for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Display&lt;/strong&gt; information in a beautiful way;&lt;/li&gt;
&lt;li&gt;Catch the &lt;strong&gt;user inputs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user inputs are interpreted and trigger a dedicated action from the domain layer. If required, additional data can be sent in argument of this action.&lt;/p&gt;

&lt;p&gt;The information displayed comes from the selectors exposed. The Observables are used in the template and no business logic should be applied to them.&lt;/p&gt;

&lt;p&gt;Those two only responsibilities make the components stateless, no logic is executed from information handled by the component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clients &amp;amp; infrastructure
&lt;/h3&gt;

&lt;p&gt;The infrastructure layers are dependencies needed by the domain layer to perform its actions. It can be web clients, communications with Local storage, or any other dependency that can be abstracted from the domain layer.&lt;/p&gt;

&lt;p&gt;The infrastructure layer contains services with &lt;strong&gt;very simple code that is only related to the usage of the dependency&lt;/strong&gt;. Optionally, it can contain mappers if needed.&lt;/p&gt;

&lt;p&gt;Client service example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;){}&lt;/span&gt;

    &lt;span class="nf"&gt;postItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;API_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Store
&lt;/h3&gt;

&lt;p&gt;The store is composed of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;state&lt;/strong&gt; of the application;&lt;/li&gt;
&lt;li&gt;Some &lt;strong&gt;reducer&lt;/strong&gt; methods that can modify the state;&lt;/li&gt;
&lt;li&gt;Some &lt;strong&gt;selectors&lt;/strong&gt;, being Observables that emit the modifications of the state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should only contain &lt;strong&gt;store-related logic&lt;/strong&gt;. No business logic and no call to another infrastructure layer.&lt;/p&gt;

&lt;p&gt;The store can be implemented using any technology. You can either use a library like &lt;a href="https://ngrx.io/" rel="noopener noreferrer"&gt;NgRx&lt;/a&gt; or &lt;a href="https://www.ngxs.io/" rel="noopener noreferrer"&gt;NGXS&lt;/a&gt;. Another solution is to create your own store using a &lt;code&gt;BehaviorSubject&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's focus on the store
&lt;/h2&gt;

&lt;p&gt;Let's come back to the store and how to implement it. When choosing the store you will use, you need to select the one that respects your architecture. You need to make sure that this store is hidden behind an abstraction to not pollute your domain layer with store-related code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NgRx&lt;/strong&gt; could be your choice, but it's maybe not the right one.&lt;/p&gt;
&lt;h3&gt;
  
  
  The issue with NgRx
&lt;/h3&gt;

&lt;p&gt;Here is the state management proposed by &lt;strong&gt;NgRx&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fm3x759pdg9uznkd64kca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fm3x759pdg9uznkd64kca.png" alt="NgRx State Management"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NgRx&lt;/strong&gt; comes with a concept that breaks our architectural rules: the &lt;strong&gt;effects&lt;/strong&gt;. Using the concept of effects, you execute business logic in the store layer and directly contact the client layer. &lt;strong&gt;You end up with logic being executed in two places: the domain layer and the store layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NgRx&lt;/strong&gt; is great, but it comes with its proper architecture which is not compatible with our SCA architecture. Except if you remove the use of effects. &lt;/p&gt;

&lt;p&gt;Another solution could be to create a simple custom store.&lt;/p&gt;
&lt;h3&gt;
  
  
  Custom store
&lt;/h3&gt;

&lt;p&gt;State, actions, selectors and reducers, those 4 store concepts can be built around a &lt;code&gt;BehaviorSubject&lt;/code&gt;. This kind of observable is a great help to play with data.&lt;/p&gt;

&lt;p&gt;Here is an example of a custom state:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="na"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * This method provides an observable representing a part of the state.
   * @param selectFn defines a method that select a subpart U the state T
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;select&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;selectFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectFn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * This method is used to update the state
   * @param reduceFn defines a method that transform the state to another state
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;reduceFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduceFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;select&lt;/code&gt; method will be used by the selectors. The &lt;code&gt;update&lt;/code&gt; method will reduce the state according to the action.&lt;/p&gt;

&lt;p&gt;But it's not enough, this store needs to be instantiated and used by a service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nx"&gt;items$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;item$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;initialItems&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The service exposes selectors and actions that have a meaning for the domain layer. It is then ready to be used by the domain layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof of Concept Project
&lt;/h2&gt;

&lt;p&gt;I made a little playground application In Angular and Spring Boot. The frontend part uses the SCA architecture as described above. Take a look to see a concrete example!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Wood-Chopper/task-manager-playground" rel="noopener noreferrer"&gt;Task Manager Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next step
&lt;/h2&gt;

&lt;p&gt;If we take a look at the graph of the SCA architecture, we notice that the dependencies lead from the components to the infrastructure layers. Meaning that it's possible to inject a client into a component.&lt;/p&gt;

&lt;p&gt;Of course, this is wrong, but there is a solution to avoid that: The inversion of dependency. Those of you who follow my blog know that I have made a little POC of &lt;a href="https://dev.to/jnavez/make-your-microservices-tastier-by-cooking-them-with-a-sweet-onion-34n2"&gt;how to apply the Onion Architecture on a SpringBoot project&lt;/a&gt;. The next step is to apply the same principles to the SCA architecture.&lt;/p&gt;

&lt;p&gt;So hold on and prepare yourself for the next article: The &lt;strong&gt;SCAO architecture:&lt;/strong&gt; &lt;em&gt;the Simple and Clean Angular Onion architecture&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Make your microservices tastier by using the Onion architecture</title>
      <dc:creator>Jérôme Navez</dc:creator>
      <pubDate>Thu, 25 May 2023 23:03:59 +0000</pubDate>
      <link>https://dev.to/jnavez/make-your-microservices-tastier-by-cooking-them-with-a-sweet-onion-34n2</link>
      <guid>https://dev.to/jnavez/make-your-microservices-tastier-by-cooking-them-with-a-sweet-onion-34n2</guid>
      <description>&lt;p&gt;Most of the traditional architectures are subject to raising issues of separation of concerns by increasing the coupling between the component. Being too permissive, those architectures stay in the theoretical concepts and do not force the developers to apply its principles.&lt;/p&gt;

&lt;p&gt;Jump to the Onion architecture&lt;/p&gt;

&lt;h1&gt;
  
  
  The Layered Architecture
&lt;/h1&gt;

&lt;p&gt;The most natural architecture when building a microservice is the Layered architecture. The Layered architecture provides guidelines to separate your service into 3 layers, from the presentation to the database. But nothing stops the developers from using entities and repositories in the presentation layer. This is mainly because of the direction of the dependencies going from the presentation to the persistence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmiltitsu5p1ga84wj9ep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmiltitsu5p1ga84wj9ep.png" alt="The Layered architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compared to the Layered architecture, the Onion architecture provides a similar way of separating your classes in modules, but by adding the usage of a specific pattern to solve this dependency issue.&lt;/p&gt;

&lt;p&gt;By browsing the web, you can find many documents about the Onion architecture, some terms that you could see in those documents may differ from the terms used in this article. Different terms, but same principles.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Onion Architecture
&lt;/h1&gt;

&lt;p&gt;Without further notice, let’s jump into the Onion architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Flddpekdgtrxi4nm64k3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Flddpekdgtrxi4nm64k3h.png" alt="The Onion architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The center of the graph is the &lt;strong&gt;domain model&lt;/strong&gt;: our business objects and the relations between those objects. Those objects are “clean” and are only meant to describe our business in the best possible way. By clean, I mean that they don’t contain any JSON, JPA, or XML annotations.&lt;/p&gt;

&lt;p&gt;Around the domain model, we find our &lt;strong&gt;domain services&lt;/strong&gt;. This is the business logic, our use-cases. The domain services strongly rely on the domain objects.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;controllers&lt;/strong&gt; (and the scheduled jobs) are the entry modules of the architecture. Thus they need to call the domain services to respond to the frontend or other clients.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;persistence&lt;/strong&gt; module and the &lt;strong&gt;clients&lt;/strong&gt; module are part of the infrastructure. Here, “Infrastructure” is a conceptual term used to group all the modules related to persistence, external communications, and any other module that the domain needs to process its tasks. The term “clients” refer to components that interact with other microservices or with external services. They are the clients of those services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principle
&lt;/h2&gt;

&lt;p&gt;The base principle of the Onion architecture is that the &lt;strong&gt;module dependencies lead to the domain module&lt;/strong&gt;. Meaning that the persistence module and the clients depend on the domain module. This is the main difference with the Layered rchitecture where the dependency go from the domain to the persistence module.&lt;/p&gt;

&lt;p&gt;More generically, &lt;strong&gt;the external layers depend on the inner layers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This ecosystem can be represented as an onion. &lt;strong&gt;A microservice project is therefore an onion&lt;/strong&gt;. The center is sweet and must be protected from outside threats. The Onion architecture enhances this protection by blocking the domain module from accessing the infrastructure layer.&lt;/p&gt;

&lt;p&gt;While the &lt;strong&gt;Layered architecture provides guidelines&lt;/strong&gt; to structure and to place our code in the right place, the &lt;strong&gt;Onion architecture provides barriers&lt;/strong&gt; to force the devs to apply those guidelines. That’s what makes this architecture so strong.&lt;/p&gt;

&lt;p&gt;Let’s zoom into the presentation layer and the way it interacts with the domain module.&lt;/p&gt;

&lt;h1&gt;
  
  
  Presentation Layer And Facades
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.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%2Famhikb83z6w4e4hnjalu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Famhikb83z6w4e4hnjalu.png" alt="The presentation module and its interaction with the domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Facades are not defined in the Onion architecture but are nice to have. In our case, they can help us to have a clearer view of our presentation module.&lt;/p&gt;

&lt;p&gt;Each &lt;strong&gt;RestController&lt;/strong&gt; contains very little logic and has its Facade.&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;@Service&lt;/span&gt;
&lt;span class="nd"&gt;@Validated&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&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;TaskManagerFacade&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="cm"&gt;/* dependencies: mapper, domain service */&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;DtoMapper&lt;/span&gt; &lt;span class="n"&gt;dtoMapper&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;TaskService&lt;/span&gt; &lt;span class="n"&gt;taskService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Secured&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ROLE_VIEWER"&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TaskDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TaskDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTasks&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;dtoMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Secured&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ROLE_EDITOR"&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;TaskDto&lt;/span&gt; &lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;TaskDto&lt;/span&gt; &lt;span class="n"&gt;taskDto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dtoMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toModel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskDto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;savedTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskService&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;task&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;dtoMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedTask&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 Facades follow this structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mapping the DTO arguments into domain models &lt;strong&gt;(DTO → Model)&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calling&lt;/strong&gt; the domain service;&lt;/li&gt;
&lt;li&gt;Mapping and returning the result into a DTO &lt;strong&gt;(Model → DTO)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More roles are given to the Facades as they act as &lt;strong&gt;guardians of our microservice&lt;/strong&gt; for aggressions coming from the outside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; and access (&lt;code&gt;@PreAuthorize&lt;/code&gt;, &lt;code&gt;@Secured&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;DTO &lt;strong&gt;validations&lt;/strong&gt; (with &lt;code&gt;@Validated&lt;/code&gt; and &lt;code&gt;@Valid&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on your business, a Facade could also “link” domain services between them and act as an orchestrator of services. In this case, more logic could be written in Facades. As long as no logic is executed on DTOs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Persistence Layer, Gateways, And Adapters
&lt;/h1&gt;

&lt;p&gt;As stated above, the inner layer needs the infrastructure layer to process its tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fzvkgjh7glukifxbh6135.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzvkgjh7glukifxbh6135.png" alt="The persistence module and its interaction with the domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take the example of a business use case that needs to store information. While the more natural way would be to import a repository in the service, the Onion architecture relies on another pattern to achieve this, the &lt;strong&gt;inversion of dependency&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inversion of dependency
&lt;/h2&gt;

&lt;p&gt;The domain module will define an interface containing all the methods he needs to communicate with a persistence module, the &lt;strong&gt;Gateway&lt;/strong&gt;. The Gateway contains methods with arguments and return types from the domain model.&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;PersistenceGateway&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="nf"&gt;saveTask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;task&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 way, &lt;strong&gt;the domain explicitly states&lt;/strong&gt; that it’s required to implement those methods to make the microservice work. It doesn’t care about how the methods are implemented and what technologies and libraries are used to achieve it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The persistence module is required to implement the Gateway to be compliant with the domain.&lt;/strong&gt; The &lt;strong&gt;Adapter&lt;/strong&gt; takes care of this responsibility and is the entry point of the module. This is where the dependency from the persistence module to the domain module appears.&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;@Service&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&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;PersistenceAdapter&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PersistenceGateway&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="cm"&gt;/* dependencies: repository, mapper, query builder etc */&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;EntityMapper&lt;/span&gt; &lt;span class="n"&gt;entityMapper&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;TaskRepository&lt;/span&gt; &lt;span class="n"&gt;taskRepository&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TaskEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;taskEntities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&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;entityMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toModel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskEntities&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;Task&lt;/span&gt; &lt;span class="nf"&gt;saveTask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;taskEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entityMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;savedTaskEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskRepository&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;taskEntity&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;entityMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toModel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedTaskEntity&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;Those method implementations follow this structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mapping the arguments into entities or queries &lt;strong&gt;(Model → Entity)&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt; the query;&lt;/li&gt;
&lt;li&gt;Mapping and returning the query result into a domain model &lt;strong&gt;(Entity → Model)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Adapter needs to adapt itself to the Gateway. Most of the time, one Adapter mechanism will be needed to communicate. But as for every class, if the number of methods grows too much, it might be wise to split the Adapters and the Gateways into multiple classes.&lt;/p&gt;

&lt;p&gt;This Gateway/Adapter is transposable to other infrastructure modules as the clients module. In this case, the mapper would map between our model and DTOs provided by the external service.&lt;/p&gt;

&lt;p&gt;We can see &lt;strong&gt;multiple advantages&lt;/strong&gt; to this dependency inversion, here are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance Domain Driven Design;&lt;/li&gt;
&lt;li&gt;Protect our model from API changes in Clients;&lt;/li&gt;
&lt;li&gt;Possibility to have multiple Adapters for one Gateway;&lt;/li&gt;
&lt;li&gt;Easier to test our domain;&lt;/li&gt;
&lt;li&gt;Domain being independent of any dependency choice.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Running everything in a Spring Boot Project
&lt;/h1&gt;

&lt;p&gt;Now that we have our domain, presentation, and persistence modules, we want to launch everything in a &lt;strong&gt;Spring Boot application&lt;/strong&gt;. To achieve this, we need an application module.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

├── spring-project
    ├── app
    ├── domain
    ├── persistence
    └── presentation


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Application module
&lt;/h1&gt;

&lt;p&gt;This module is a &lt;strong&gt;no-code module&lt;/strong&gt;. Its responsibility is only to provide a way to make everything run together. It imports persistence, presentation, and domain modules in its &lt;code&gt;pom.xml&lt;/code&gt; (or &lt;code&gt;build.gradle&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;project&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.woodchopper.tuto.onion&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;presentation&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.woodchopper.tuto.onion&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;domain&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.woodchopper.tuto.onion&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;persistence&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The only source class present in this module is the Spring Boot application class containing the main method:&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;Application&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&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;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Application&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="n"&gt;args&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 module also contains the different property files needed to run the application. The &lt;strong&gt;integration tests&lt;/strong&gt; responsible fortesting the flows from the controllers to the repository are written in this module.&lt;/p&gt;

&lt;h1&gt;
  
  
  What and how to test?
&lt;/h1&gt;

&lt;p&gt;Ideally, we should be able to cover the entire project with our tests. Two kinds of tests can be made:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit testing on a targeted class;&lt;/li&gt;
&lt;li&gt;Integration testing on an endpoint.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unit tests
&lt;/h2&gt;

&lt;p&gt;Each class containing logic code needs to be tested. logic code means business logic but also mapping logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration tests
&lt;/h2&gt;

&lt;p&gt;Those tests provide a way to cover the global microservice flows. The goal is not to cover each specific case of the mapper or the domain services.&lt;/p&gt;

&lt;p&gt;This will also allow the developer to cover the Adapters and Facades. Hence, the security and the validation behaviors will be tested.&lt;/p&gt;

&lt;p&gt;Those tests are located in the &lt;strong&gt;application module&lt;/strong&gt; since they need the Spring Boot context to be launched. They will mainly use &lt;strong&gt;MockMvc&lt;/strong&gt; as their main tool.&lt;/p&gt;

&lt;h1&gt;
  
  
  Proof of Concept Project
&lt;/h1&gt;

&lt;p&gt;I made a little playground application In Angular and Spring Boot. The backend part uses the Onion architecture as described above. Take a look to see a concrete example!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Wood-Chopper/task-manager-playground" rel="noopener noreferrer"&gt;Task Manager Playground&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We saw a way to implement the Onion architecture in a SpringBoot microservice. While this architecture certainly comes with more classes than the Layered architecture, its structure enhances the maintainability by imposing a strong structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Angular Access Right And Feature Toggle By Extending NgIf!</title>
      <dc:creator>Jérôme Navez</dc:creator>
      <pubDate>Thu, 13 Apr 2023 13:39:48 +0000</pubDate>
      <link>https://dev.to/jnavez/angular-access-right-and-feature-switch-as-easy-as-ngif-4a8k</link>
      <guid>https://dev.to/jnavez/angular-access-right-and-feature-switch-as-easy-as-ngif-4a8k</guid>
      <description>&lt;p&gt;Jump to final solution&lt;/p&gt;

&lt;p&gt;During your Angular journey, you could be invested into a development that implies hiding elements to some kind of users depending &lt;strong&gt;access right&lt;/strong&gt; or roles. You could even need to &lt;strong&gt;hide complete features&lt;/strong&gt; from you Angular client waiting for the backend to be implemented or waiting for the feature to be officially released to the public.&lt;/p&gt;

&lt;p&gt;I can already hear it from you, when it comes to display or hide components or other elements from a template, the first thing that comes in mind is to create a directive. It's reusable and &lt;strong&gt;we love reusable things&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's continue our story with our second example. We need to implement a directive that hide the element based on a given feature. Let us suppose that we have a feature called: &lt;em&gt;githubLogin&lt;/em&gt;. Basically, this feature active the authentication via GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the directive (the naive way)
&lt;/h2&gt;

&lt;p&gt;And Abracadabra, we have our nice &lt;code&gt;FeatureToggleDirective&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[feature]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;FeatureToggleDirective&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;viewContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDisabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's used like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;[feature]=&lt;/span&gt;&lt;span class="s"&gt;"'githubLogin'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login via GitHub&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meaning that the button &lt;em&gt;Login via GitHub&lt;/em&gt; is displayed if the feature is enabled.&lt;/p&gt;

&lt;p&gt;So here we are, we created our directive, and you noticed that I used &lt;code&gt;ViewContainerRef&lt;/code&gt; to hide the content. It's a choice, I could also inject &lt;code&gt;ElementRef&lt;/code&gt; and use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to hide the content. Both solutions are valid, and we will go further in the comparison since it's not the goal of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can we do better?
&lt;/h2&gt;

&lt;p&gt;Of course, we can do better! What if we want to change the behavior of this directive to be more dynamic and flexible.&lt;/p&gt;

&lt;p&gt;For example, being able to use it when the feature name is given asynchronously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;[feature]=&lt;/span&gt;&lt;span class="s"&gt;"featureName$ | async"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login via GitHub&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would need to use a setter or implement &lt;code&gt;OnChange.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We could also decide to display a message explaining why this feature is disabled. By providing a fallback template to the directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;[feature]=&lt;/span&gt;&lt;span class="s"&gt;"'githubLogin'"&lt;/span&gt; &lt;span class="na"&gt;[featureFallbackTemplate]=&lt;/span&gt;&lt;span class="s"&gt;"fallback"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login via GitHub&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#fallback&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sorry, the GitHub feature is not yet available&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is so much work to do to make our directive completely robust. At some point, it begins to be as dynamic and robust as another directive that we all know...&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending &lt;code&gt;NgIf&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The subtitle says it all, why not reusing the code of &lt;code&gt;NgIf&lt;/code&gt;. It has been proved that it works. It's the most used directive in the Angular world (&lt;em&gt;"ngIf"&lt;/em&gt; gives 4M file results in Github!). So what do we do ? Do we copy the NgIf solution? What about &lt;strong&gt;extending NgIf&lt;/strong&gt;? Yes, sounds good!&lt;/p&gt;

&lt;p&gt;Let's take a look at the &lt;a href="https://github.com/angular/angular/blob/main/packages/common/src/directives/ng_if.ts"&gt;NgIf code&lt;/a&gt;. We notice 4 methods: 3 setters and one private method where all the magic occurs.&lt;/p&gt;

&lt;p&gt;Since our directive has its own selector name &lt;code&gt;feature&lt;/code&gt;, we need to rename the setters with &lt;code&gt;feature&lt;/code&gt;, &lt;code&gt;featureThen&lt;/code&gt;, and &lt;code&gt;featureElse&lt;/code&gt;. Each of those methods will act as a proxy and call the corresponding setter in &lt;code&gt;NgIf&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;We also need to add the &lt;code&gt;FeatureService&lt;/code&gt; logic in the feature setter. Our condition returns a &lt;code&gt;boolean&lt;/code&gt;, so we set the type of the &lt;code&gt;NgIf&lt;/code&gt; to &lt;code&gt;boolean&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[feature]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;FeatureToggleDirective&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;NgIf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngIf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;featureThen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NgIfContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;|&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngIfThen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;featureElse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NgIfContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;|&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngIfElse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templateRef&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="na"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureService&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="na"&gt;_viewContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NgIfContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_viewContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, you can now use all the power of &lt;code&gt;NgIf&lt;/code&gt; with your feature toggle directive! Amazing, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Some usage examples
&lt;/h2&gt;

&lt;p&gt;Some examples of how we can use our directive:&lt;/p&gt;

&lt;p&gt;Simple form with shorthand syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;*feature=&lt;/span&gt;&lt;span class="s"&gt;"'githubLogin'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;GiHub login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple form with expanded syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;[feature]=&lt;/span&gt;&lt;span class="s"&gt;"'githubLogin'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;GiHub login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shorthand form with an &lt;code&gt;else&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;*feature=&lt;/span&gt;&lt;span class="s"&gt;"'githubLogin'; else fallback"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;GiHub login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#fallback&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;Sorry, the feature is not yet available&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shorthand form with &lt;code&gt;then&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt; blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*feature=&lt;/span&gt;&lt;span class="s"&gt;"'githubLogin'; then github; else fallback"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;GiHub login&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#github&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;GiHub login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#fallback&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;Sorry, the feature is not yet available&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Working example
&lt;/h2&gt;

&lt;p&gt;Take a look at the working online example here: &lt;a href="https://stackblitz.com/edit/angular-ivy-7fkk6h?file=src/app/app.component.html"&gt;StackBlitz&lt;/a&gt;. Play with it and fork it!&lt;/p&gt;

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

&lt;p&gt;We created a highly reusable directive based on a simple feature toggle example. There are plenty of other features that could reuse &lt;code&gt;NgIf&lt;/code&gt;. I hope this article will give you more ideas and uses cases to build even more directives of this kind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
