<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[REDA's BLOG]]></title><description><![CDATA[Knowledge sharing believer, passionate about Architecture, Java and OSS and everything in between. Also football addict 👌]]></description><link>https://redamessoudi.com/</link><image><url>https://redamessoudi.com/favicon.png</url><title>REDA&apos;s BLOG</title><link>https://redamessoudi.com/</link></image><generator>Ghost 3.42</generator><lastBuildDate>Thu, 15 Oct 2026 06:57:38 GMT</lastBuildDate><atom:link href="https://redamessoudi.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Optimized docker images for Spring Boot applications with layering feature]]></title><description><![CDATA[<p>Since Spring Boot 2.3, support for building jar files with contents separated into layers has been added to the Maven and Gradle plugins.</p><p>The question is : <strong>How this layering can help us to improve our docker images ?</strong></p><p>Let's see how Spring Boot defines layering :</p><blockquote>The layering separates the jar’</blockquote>]]></description><link>https://redamessoudi.com/optimized-docker-images-for-spring-boot-apps/</link><guid isPermaLink="false">5faccd8a28d3222da3b9bbec</guid><category><![CDATA[Java]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Reda Messoudi]]></dc:creator><pubDate>Mon, 16 Nov 2020 18:59:23 GMT</pubDate><media:content url="https://redamessoudi.com/content/images/2020/11/post_image-3.png" medium="image"/><content:encoded><![CDATA[<img src="https://redamessoudi.com/content/images/2020/11/post_image-3.png" alt="Optimized docker images for Spring Boot applications with layering feature"><p>Since Spring Boot 2.3, support for building jar files with contents separated into layers has been added to the Maven and Gradle plugins.</p><p>The question is : <strong>How this layering can help us to improve our docker images ?</strong></p><p>Let's see how Spring Boot defines layering :</p><blockquote>The layering separates the jar’s contents based on how frequently they will change.</blockquote><p>Spring Boot uses <em>fat Jar</em> as default packaging format. If we inspect our application by checking this <em>fat Jar</em>, we can observe that our business code (application) forms a small part of this big jar file. The rest of parts forms the framework, external dependencies and some internal dependencies as we'll see with multi-module projects.</p><h1 id="code-example">Code example</h1><p>This post has a working code example available <strong><a href="https://github.com/redamessoudi/optimized-docker-image-for-springboot">here</a></strong>.</p><h2 id="how-to-read">How to read</h2><p>During this post, I'll go progressively through the optimization of our docker image based on a sample of Spring Boot application.</p><p>Our goal through this post is to reach the following result:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/11/springboot_optimizeddockerimage-2.png" class="kg-image" alt="Optimized docker images for Spring Boot applications with layering feature"><figcaption>Optimization to reach</figcaption></figure><h3 id="base-code">Base code</h3><p>Let's create a basic Spring Boot application with a simple <code>/hello</code> endpoint to use as sample for the following. You can get it under branch '<strong><a href="https://github.com/redamessoudi/optimized-docker-image-for-springboot/tree/nodocker">/nodocker</a></strong>'.</p><h3 id="basic-dockerization-of-spring-boot-application">Basic dockerization of Spring Boot application</h3><!--kg-card-begin: markdown--><h4 id="code">Code</h4>
<!--kg-card-end: markdown--><p>The code of this section is available under branch '<strong><a href="https://github.com/redamessoudi/optimized-docker-image-for-springboot/tree/initdockerization">/initdockerization</a></strong>'.</p><!--kg-card-begin: markdown--><h4 id="details">Details</h4>
<!--kg-card-end: markdown--><p>As a first step, we'll dockerize our sample application by a simple Dockerfile which looks like:</p><figure class="kg-card kg-code-card"><pre><code class="language-dockerfile">FROM adoptopenjdk/openjdk11:alpine-jre
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
EXPOSE 8081
ENTRYPOINT ["java","-jar","/application.jar"]</code></pre><figcaption>Dockerfile for a basic dockerization</figcaption></figure><p>Now we can :</p><!--kg-card-begin: markdown--><ul>
<li>pack our application to a <em>fat Jar</em> with Maven</li>
</ul>
<pre><code>mvn clean package
</code></pre>
<ul>
<li>and build the docker image</li>
</ul>
<pre><code>docker build -t optimized_dockerimage_springboot:0.0.1 .
</code></pre>
<!--kg-card-end: markdown--><p>By checking our image size, it's around 167 MB and by using <a href="https://github.com/wagoodman/dive">Dive</a> we can see that the application layer is 16 MB which is a significant part of the image size.</p><!--kg-card-begin: markdown--><pre><code>dive optimized_dockerimage_springboot:0.0.1
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/11/dive_into_initdockerization-1.png" class="kg-image" alt="Optimized docker images for Spring Boot applications with layering feature"><figcaption>Dive into basic docker image</figcaption></figure><p>If you don't have Dive or you want to continue without it, you can get similar result using:</p><!--kg-card-begin: markdown--><p><code>docker history --format &quot;{{.ID}} {{.CreatedBy}} {{.Size}}&quot; optimized_dockerimage_springboot:0.0.1</code></p>
<!--kg-card-end: markdown--><p>You would say 16 MB isn't such big size but here our sample application contains only one class with some lines, but consider the sizes of real production-ready applications (<em>fat Jars</em>), it can more larger as the complexity and dependencies growth.</p><h3 id="what-s-the-problem-with-large-size-application">What's the problem with large size application ? </h3><p>The aim of docker images is to be lightweight and reusable as much as possible so our deployment and release processes can be faster.</p><p>With large docker images and frequent release cycle we can end by a lot of gigabytes of storage space and increase the network traffic which can be a <em>very</em> bad design specially in cloud environment and when you pay for the traffic usage and storage.</p><p>Another problematic thing with unoptimized docker images is <strong>performance </strong>during <strong>Scheduling</strong> process.</p><h3 id="what-s-scheduling">What's Scheduling ? </h3><p>In a nutshell, scheduling is how containers are placed and run on your instance.<br>Take one container with 1GB, managing it couldn't be tricky but what if you have multiple containers with 1GB ? </p><p>Every time, pulling this 1GB from your registry causes a long scheduling process and long build times in CI pipelines.</p><p>Think about scalability, think about time needed by your orchestration system to place this containers on your instance(s) and think about problems that you can face every time you deploy your 1GB containers.</p><h3 id="add-new-feature-to-our-application">Add new feature to our application</h3><p>Now we want to add a new endpoint to our controller which means new feature and new release of our application.</p><p>Once the new feature is implemented and our new application version is released we can use the same <strong>basic dockerization</strong> and build our new docker image version right ?</p><p>But the problem here is that our basic dockerization can't see the small size and difference added by our new feature. This new docker image will be built with all our Spring framework dependencies, internal and external dependencies instead of considering the thin change on our business code.</p><h3 id="can-we-optimize">Can we optimize ?</h3><p>Of course we can.</p><p>As explained in the intro, Spring Boot 2.3 made it possible to extract content of our <em>fat Jar</em> without any additional plugins. </p><p>This possibility allows us to easily include additional separation between our project dependencies.</p><h3 id="optimized-docker-image">Optimized docker image</h3><!--kg-card-begin: markdown--><h4 id="code">Code</h4>
<!--kg-card-end: markdown--><p>The code of this section is available under branch '<strong><a href="https://github.com/redamessoudi/optimized-docker-image-for-springboot/tree/optimized_dockerimage">/optimized_dockerimage</a></strong>'</p><!--kg-card-begin: markdown--><h4 id="layering">Layering</h4>
<!--kg-card-end: markdown--><p>Spring Boot splits the content of <em>*fat Jar*</em> to 4 layers but by default this layering feature is disabled and needs to be explicitly enabled with the Spring Boot Maven plugin:</p><figure class="kg-card kg-code-card"><pre><code class="language-xml">&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
        &lt;configuration&gt;
            &lt;layers&gt;
                &lt;enabled&gt;true&lt;/enabled&gt;
            &lt;/layers&gt;
        &lt;/configuration&gt; 
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;</code></pre><figcaption>Enable layering feature in Spring Boot 2.3 project</figcaption></figure><!--kg-card-begin: markdown--><p>The 4 layers by default are like following :</p>
<ul>
<li>
<p><code>dependencies</code> : Contains dependency without SNAPSHOT version</p>
</li>
<li>
<p><code>spring-boot-loader</code> : Includes JAR loader classes</p>
</li>
<li>
<p><code>snapshot-dependencies</code> : Contains any dependency with SNAPSHOT version</p>
</li>
<li>
<p><code>application</code> : Includes application classes and resources</p>
</li>
</ul>
<p>And this <code>application</code> layer will be our main changing layer while our development progress.</p>
<p>To obtain this layering information, we do:</p>
<pre><code>java -Djarmode=layertools -jar target/*.jar list
</code></pre>
<p>Until now we just got what compound the layers of our <em>fat Jar</em>.</p>
<p>Next step is to extract those layers to create an optimized docker image. Hopefully, the <code>-Djarmode=layertools</code> system property exists with <code>extract</code> command in aim to extract layers from the jar file and unpack it into seperate directories.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="takeaway">Take-away</h4>
<p>If you want to <code>extract</code> in a specific folder/destination, just add <code>--destination</code> argument like:</p>
<pre><code>java -Djarmode=layertools -jar target/*.jar extract --destination target/extracted</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="builddockerimage">Build docker image</h4>
<!--kg-card-end: markdown--><p>A Docker image is composed of a stack of layers each representing an instruction in our Dockerfile, so we can use those extracted layers from <em>fat Jar</em> to construct Docker layers that change the least. </p><p>Let's build our docker image while taking benefit of layering feature and <a href="https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds">multi-stage build</a>.</p><figure class="kg-card kg-code-card"><pre><code class="language-dockerfile">FROM adoptopenjdk/openjdk11:alpine-jre as builder
# First stage : Extract the layers
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk/openjdk11:alpine-jre as runtime
# Second stage : Copy the extracted layers
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
CMD ["java", "org.springframework.boot.loader.JarLauncher"]</code></pre><figcaption>Dockerfile for the optimized dockerization</figcaption></figure><!--kg-card-begin: markdown--><p>You may notice that no application JAR to run with <code>java -jar</code>. Instead we use the <code>org.springframework.boot.loader.Launcher</code> class which is a special bootstrap class that is used as an executable jar’s main entry point. It's the actual Main-Class in the jar file, and it is used to setup an appropriate URLClassLoader and call the <code>main()</code> method.</p>
<p>Now we can :</p>
<ul>
<li>pack our application to a <strong>layered</strong> <em>fat Jar</em> with Maven:</li>
</ul>
<pre><code>mvn clean package
</code></pre>
<ul>
<li>and build the docker image:</li>
</ul>
<pre><code>docker build -t optimized_dockerimage_springboot:0.0.2 .
</code></pre>
<p>By verifying our <strong>optimized</strong> docker image size, it's around 167 MB (same size) but by using <a href="https://github.com/wagoodman/dive">Dive</a> we can see that the application code is only <strong>5.7 kB</strong> which is a very lightweight part of the image size.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/11/dive_into_optimizeddockerimage-1.png" class="kg-image" alt="Optimized docker images for Spring Boot applications with layering feature"><figcaption>Dive into optimized docker image</figcaption></figure><p>Now every time we build our docker image, existing layers that have not changed can be reused and only this layer of 5.7 kB will change/growth while delivering new releases (new features, bug fixing, ...).</p><h3 id="optimized-docker-image-with-multi-module-project">Optimized docker image with multi-module project</h3><p>What we did until now was good for most applications but it's possible that in some projects we need to go differently than the out-of-the-box provided by Spring Boot.</p><p>For example, we might have some company dependencies that change less frequently than our application or we can have a multi-module project with internal dependencies with different change cadence. We'll cover all that in this section.</p><!--kg-card-begin: markdown--><h4 id="code">Code</h4>
<!--kg-card-end: markdown--><p>The code of this section is available under branch '<a href="https://github.com/redamessoudi/optimized-docker-image-for-springboot/tree/multimodule_optimized_dockerimage">/multimodule_optimized_dockerimage</a>'.</p><!--kg-card-begin: markdown--><h4 id="multimoduleproject">Multi-module project</h4>
<p>First let's change our sample application to a multi-module maven project.</p>
<p>Our project will look like:</p>
<ul>
<li><code>domain</code> : Contains our module of domain classes (models, ...)</li>
<li><code>application</code> : Contains our controllers, ...</li>
<li>and you can also add if you want other modules like <code>persistence</code>, <code>security</code>, ...</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/11/multimodule_project_structure-1.png" class="kg-image" alt="Optimized docker images for Spring Boot applications with layering feature"><figcaption>Structure of multimodule project with maven</figcaption></figure><!--kg-card-begin: markdown--><p>We need to adjust our different <code>pom.xml</code> files, you can take a look on the dedicated branch of this section.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="customlayersconfiguration">Custom layers configuration</h4>
<p>Let's tune how layers are created and add new ones. This can be done using a separate <code>layers.xml</code> file that should be :</p>
<ul>
<li>registred (<code>application/pom.xml</code>):</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-code-card"><pre><code class="language-xml">    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;id&gt;repackage&lt;/id&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;repackage&lt;/goal&gt;
                        &lt;/goals&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
                &lt;configuration&gt;
                    &lt;layers&gt;
                        &lt;enabled&gt;true&lt;/enabled&gt;
                        &lt;includeLayerTools&gt;true&lt;/includeLayerTools&gt;
                        &lt;configuration&gt;${project.basedir}/src/layers.xml&lt;/configuration&gt;
                    &lt;/layers&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;</code></pre><figcaption>Indicate the path to layers.xml file</figcaption></figure><!--kg-card-begin: markdown--><ul>
<li>configured (<code>application/src/layers.xml</code>):</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-code-card"><pre><code class="language-xml">&lt;layers xmlns="http://www.springframework.org/schema/boot/layers"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
                      https://www.springframework.org/schema/boot/layers/layers-2.3.xsd"&gt;
  &lt;application&gt;
    &lt;into layer="spring-boot-loader"&gt;
      &lt;include&gt;org/springframework/boot/loader/**&lt;/include&gt;
    &lt;/into&gt;
    &lt;into layer="application"/&gt;
  &lt;/application&gt;
  &lt;dependencies&gt;
    &lt;into layer="snapshot-dependencies"&gt;
      &lt;include&gt;*:*:*SNAPSHOT&lt;/include&gt;
    &lt;/into&gt;
    &lt;into layer="modules-dependencies"&gt;
      &lt;include&gt;com.redamessoudi.optimizeddockerimage:*:*&lt;/include&gt;
    &lt;/into&gt;
    &lt;into layer="organization-dependencies"&gt;
      &lt;include&gt;com.redamessoudi*:*:*&lt;/include&gt;
    &lt;/into&gt;
    &lt;into layer="dependencies"/&gt;
  &lt;/dependencies&gt;
  &lt;layerOrder&gt;
    &lt;layer&gt;dependencies&lt;/layer&gt;
    &lt;layer&gt;spring-boot-loader&lt;/layer&gt;
    &lt;layer&gt;organization-dependencies&lt;/layer&gt;
    &lt;layer&gt;modules-dependencies&lt;/layer&gt;
    &lt;layer&gt;snapshot-dependencies&lt;/layer&gt;
    &lt;layer&gt;application&lt;/layer&gt;
  &lt;/layerOrder&gt;
&lt;/layers&gt;</code></pre><figcaption>Define the content of layers.xml</figcaption></figure><!--kg-card-begin: markdown--><p>The configuration file above describes how the jar can be separated into layers, and the order of those layers.</p>
<p>The layers XML format is defined in three sections:</p>
<ul>
<li>
<p><code>application</code> : defines how the application classes and resources should be layered.</p>
</li>
<li>
<p><code>dependencies</code> : defines how dependencies should be layered.</p>
</li>
<li>
<p><code>layerOrder</code> : defines the order that the layers should be written.</p>
</li>
</ul>
<p>More information about different blocks of this file can be found under <a href="https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/maven-plugin/reference/html/#repackage-layers-configuration">official documentation</a>.</p>
<p>Keep in mind that <code>include</code> schema is <code>group:artifact[:version]</code> and allows to use Ant matcher patterns.</p>
<p>As we want to add a :</p>
<ul>
<li>layer containing all modules dependencies (<code>&lt;include&gt;com.redamessoudi.optimizeddockerimage:*:*&lt;/include&gt;</code>).</li>
<li>layer containing all organization/company dependencies (<code>&lt;include&gt;com.redamessoudi*:*:*&lt;/include&gt;</code>)</li>
</ul>
<p>regardless of their version, so we used wildcard to match every <code>artifactId</code> and <code>version</code> with the specified <code>groupId</code>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="dockerlayersoptimization">Docker layers optimization</h4>
<p>Let's adjust our Dockerfile to support the 2 new layers (<code>modules-dependencies</code> and <code>organization-dependencies</code>).</p>
<p>Our new Dockerfile will look like:</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-code-card"><pre><code class="language-dockerfile">FROM adoptopenjdk/openjdk11:alpine-jre as builder
# First stage : Extract the layers
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk/openjdk11:alpine-jre as runtime
# Second stage : Copy the extracted layers
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader ./
COPY --from=builder application/organization-dependencies ./
COPY --from=builder application/modules-dependencies ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
CMD ["java", "org.springframework.boot.loader.JarLauncher"]</code></pre><figcaption>Dockerfile for the optimized dockerization of multi-module project</figcaption></figure><!--kg-card-begin: markdown--><p>Now if we build a new version of our docker image, you can see that we take the benefit of Docker cache.</p>
<p>Below I added small change in one of the modules and I rebuilt the docker image thus we can see all previous layers (<code>Step 1 to 18/22</code>) didn't change and took the advantage of Docker cache (<code>--&gt; using cache</code>).</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/11/docker_cache-multimodule_project-1.png" class="kg-image" alt="Optimized docker images for Spring Boot applications with layering feature"><figcaption>Docker cache with multi-stage and multi-module project</figcaption></figure><p>And <em>tadaaaa 👏, </em>we reached our goal defined in the beginning of this post which is to optimize our docker images of Spring Boot based applications with layering feature 💪</p><p>Before closing this topic, I'll add below some best practices that every docker user should think about while building image specially with Spring Boot.</p><h2 id="best-practices">Best practices</h2><p>Now we have optimized our Spring Boot and docker layers, we can see some best practices to have a secure, fast startup and readable docker image.</p><h3 id="non-root-user">Non root user</h3><!--kg-card-begin: markdown--><p>Just as in classic VM-deployments, processes should not be run with root permissions. Your application <a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege">should have privileges which are essential to perform its intended function</a>.</p>
<p>In other words, the docker image should contain a non-root user that runs the application.</p>
<p>In a Dockerfile, this can be achieved by adding another layer that adds a (system) user and group, then set it as the current user (instead of root):</p>
<pre><code>ARG USER=myuser
ARG HOME=/home/$USER
RUN addgroup --gid 1000 &quot;$USER&quot; \
  &amp;&amp; adduser -u 1000 -G &quot;$USER&quot; -h &quot;$HOME&quot; &quot;$USER&quot; --disabled-password
</code></pre>
<p>In our multi-stage build, we can add it to our second layer which is <code>runtime</code>. Complete example can be found in Dockerfile in code section of <a href="https://redamessoudi.com/optimized-docker-images-for-spring-boot-apps/optimizedmultimodule">optimized multi-module project</a>.</p>
<!--kg-card-end: markdown--><h3 id="labels">Labels</h3><!--kg-card-begin: markdown--><p>Labels are very helpful metadata to organize images, record licensing information, annotate relationships between containers, volumes, and networks, or in any way that makes sense for your business or application.</p>
<p>In a nutshell, docker images with metadata are more readable and easy/quick understandable by others.</p>
<p>Specifying label for docker Image is simple. we just need to specify it as another Dockerfile instruction.</p>
<pre><code>LABEL maintainer=&quot;contact@yourcompany.com&quot;
LABEL com.yourcompany.application.name = &quot;optimizedSBDimage&quot;
LABEL com.yourcompany.application.version = &quot;0.0.3&quot;
</code></pre>
<p>You can also manage the version value from your Maven <code>version</code> field in pom.xml while building/publishing your docker image to your repo.</p>
<p>You can check the added information under layers section with:</p>
<pre><code>docker image inspect optimized_dockerimage_springboot:0.0.3
</code></pre>
<!--kg-card-end: markdown--><h3 id="base-image">Base image</h3><!--kg-card-begin: markdown--><p>Consider your <code>FROM</code> with using small base image. There is different images whose can be used and maybe smaller than one we used in this post, but you need to know what you want in your base image and select one fills your needs.</p>
<p>We used <code>*-jre</code> base image which means that doesn't include JDK, is smaller than <code>*-jdk</code> but not all apps work with a JRE (as opposed to a JDK), but most do, and indeed some organizations enforce a rule that every app has to because of the risk of misuse of some of the JDK features (like compilation).</p>
<!--kg-card-end: markdown--><h3 id="fast-startup">Fast startup</h3><!--kg-card-begin: markdown--><p>If you want to start your app (inside a container) as quickly as possible here is some tweaks you might consider:</p>
<ul>
<li>Use Spring Boot &gt;= 2.3 and Spring &gt;= 5.1</li>
<li>Avoid actuators if you can</li>
<li>Switch off JMX with <code>spring.jmx.enabled=false</code></li>
<li>and <a href="https://spring.io/guides/topicals/spring-boot-docker">more</a></li>
</ul>
<!--kg-card-end: markdown--><h2 id="resources">Resources</h2><!--kg-card-begin: markdown--><p>Source code: <a href="https://github.com/redamessoudi/optimized-docker-image-for-springboot">https://github.com/redamessoudi/optimized-docker-image-for-springboot</a></p>
<p>Spring articles :</p>
<ul>
<li><a href="https://spring.io/guides/topicals/spring-boot-docker">Spring Boot docker</a></li>
<li><a href="https://spring.io/guides/gs/spring-boot-docker/">Getting started with docker and spring boot</a></li>
<li><a href="https://www.youtube.com/watch?v=WL7U-yGfUXA">What's new in Spring Boot 2.3</a></li>
<li><a href="https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/maven-plugin/reference/html/">Spring boot maven plugin</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Polymorphic deserialization with Jackson and no annotations]]></title><description><![CDATA[<p>Suppose I asked you to take a cup from the multiple choices in the header photo, certainly you'll ask which one to choose as there is many cups and you need something precise and maybe unique by cup to decide. </p><p>All the choices are cups, they share some common points</p>]]></description><link>https://redamessoudi.com/jackson-polymorphic-deserialization-free-annotations/</link><guid isPermaLink="false">5f8071f3ffd7c66860ae1c8b</guid><category><![CDATA[Java]]></category><dc:creator><![CDATA[Reda Messoudi]]></dc:creator><pubDate>Sun, 11 Oct 2020 21:24:04 GMT</pubDate><media:content url="https://redamessoudi.com/content/images/2020/10/eric-prouzet-5lUMTeo7-bE-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://redamessoudi.com/content/images/2020/10/eric-prouzet-5lUMTeo7-bE-unsplash.jpg" alt="Polymorphic deserialization with Jackson and no annotations"><p>Suppose I asked you to take a cup from the multiple choices in the header photo, certainly you'll ask which one to choose as there is many cups and you need something precise and maybe unique by cup to decide. </p><p>All the choices are cups, they share some common points (color, weight, ...) but maybe each one has something that the other cups don't have. This is polymorphism.</p><h2 id="code-example">Code example</h2><p>This post has a working code example available <a href="https://github.com/redamessoudi/polymorphic-deserialization">here</a>.</p><h2 id="what-s-polymorphism"><strong>What's polymorphism ?</strong></h2><p>Polymorphism is the ability to have different implementations represented by a single interface or abstract class.</p><p>This post is about how to deserialize objects by their abstract. Same idea presented below can be used to serialize objects.</p><p>Let's consider the following abstraction : </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/10/players_polymorphic_asbtraction.png" class="kg-image" alt="Polymorphic deserialization with Jackson and no annotations"><figcaption>Player abstraction</figcaption></figure><p>Suppose you have an POST endpoint which supports creation of multiple objects by abstraction. Something like : you POST /players when PLAYER can be FootballPlayer, TennisPlayer or BasketPlayer.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">@PostMapping(value = "/players", consumes = MediaType.APPLICATION_JSON_VALUE)
  ResponseEntity&lt;?&gt; createPlayer(@RequestBody Player player);</code></pre><figcaption>POST /players endpoint</figcaption></figure><h2 id="problem">Problem</h2><p>If we go directly invoking the /players endpoint, we'll face the <code><strong>InvalidDefinitionException</strong></code> as <strong>Jackson</strong> can't define to which class instance the PLAYER request body should be deserialized.</p><h2 id="what-s-jackson">What's Jackson ?</h2><p>As claimed by it's creators : </p><blockquote>Jackson has been known as "the Java JSON library" or "the best JSON parser for Java". Or simply as "JSON for Java".</blockquote><p>Simply, Jackson is a Java library to serialize and deserialize objects to/from JSON.</p><p>I'll use <strong>Spring Boot</strong> in this post but if you want to go without it, just grab the latest dependency of <a href="https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22jackson-databind%22">Jackson Databind</a> on Maven Central.</p><figure class="kg-card kg-code-card"><pre><code class="language-xml">&lt;dependency&gt;
  &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
  &lt;artifactId&gt;jackson-core&lt;/artifactId&gt;
  &lt;version&gt;VERSION_HERE&lt;/version&gt;
&lt;/dependency&gt;</code></pre><figcaption>pom.xml</figcaption></figure><h2 id="deserialization">Deserialization</h2><p>The deserialization part will have to determine which concrete class the JSON represents, and instantiate an instance of it.</p><h3 id="deserialization-using-annotation">Deserialization using annotation</h3><p>Using annotation is probably the most used technique because of it's simplicity and time-saving, but sometimes it's impossible to go with it.</p><p>Some resources describe how it can be done, you can check <a href="https://www.baeldung.com/jackson-annotations">here</a> or <a href="https://www.logicbig.com/tutorials/misc/jackson/jackson-json-type-info-annotation.html">here</a> if you are curious.</p><h3 id="deserialization-with-no-annotation">Deserialization with no annotation</h3><p>Not every project gives the possibility to add annotations on your domain classes.</p><p>Sometimes, your domain classes (Player, FootballPlayer, ...) are hidden behind an imported jar dependency and you can't access them for annotating </p><p>OR </p><p>you are using DDD and hexagonal architecture where purists say : </p><blockquote>No framework or libraries inside the domain</blockquote><p>OR </p><p>simply because of some technical constraints in your company/project.</p><p>First thing to do is to create a custom Jackson deserializer and implement the logic of deserialization.</p><p>To implement a custom deserializer, we need to create an implementation of <code>StdDeserializer</code> which is an abstract type and the base class for common Jackson deserializers.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">public class PlayerDeserializer extends StdDeserializer&lt;Player&gt; {

  public PlayerDeserializer() {
    this(null);
  }

  public PlayerDeserializer(final Class&lt;?&gt; vc) {
    super(vc);
  }

  @Override
  public Player deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
      throws IOException {
    // TODO - implement deserialization logic here
    return null;
  }</code></pre><figcaption>First draft of custom Jackson deserializer</figcaption></figure><p>Few lines above, we exposed our abstraction of Player. Let's create an enum to distinguish the different Player instances.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">public enum SportType {

  FOOTBALL("FOOTBALL"),
  TENNIS("TENNIS"),
  BASKET("BASKET");

  private final String value;

  SportType(String value) {
    this.value = value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  public static SportType fromValue(String text) {
    for (SportType sportType : SportType.values()) {
      if (String.valueOf(sportType.value).equals(text)) {
        return sportType;
      }
    }
    return null;
  }</code></pre><figcaption>SportType enum</figcaption></figure><p>As now we defined our <code>SportType</code> enum, based on that we can implement in details our <code>deserialize</code> method. Here we can take the benefit of this <code>sportType</code> field inside our abstract class PLAYER.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">@Override
  public Player deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
      throws IOException {

    final ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
    final JsonNode playerNode = mapper.readTree(jsonParser);

    final SportType sportType = SportType.fromValue(playerNode.get("sportType").asText());
    switch (sportType) {
      case FOOTBALL:
        return mapper.treeToValue(playerNode, FootballPlayer.class);
      case TENNIS:
        return mapper.treeToValue(playerNode, TennisPlayer.class);
      default:
        log.warn("Unexpected Player type : {}", sportType.toString());
        throw new IllegalStateException("Unexpected Player type : " + sportType.toString());
    }
  }</code></pre><figcaption>Deserialization logic based on submitted type of the abstract class Player</figcaption></figure><p>The last step to do before going ready for deserialization is to indicate that our <code>PlayerDeserializer</code> is a part of Jackson serializers/deserializers. Two possibilities available here : </p><ul><li>Register the <code>PlayerDeserializer</code> manually while adding it to the <em>ObjectMapper </em>(Example in the source code)<em>.</em></li></ul><p>OR</p><ul><li>As we use Spring Boot, we can use the <code>@JsonComponent</code> which do the same behavior but with less lines of code.</li></ul><p>Maybe you're asking why we have this annotation as the title indicates "FREE ANNOTATIONS"? .</p><p><code>@JsonComponent</code> is a Spring Boot annotation and not a part of Jackson and it lives in our newly created deserializer.</p><p>Another question can be : </p><blockquote><strong>What if we don't have this kind of "type" in our abstract class (e.g <code>sportType</code>)</strong> ?</blockquote><p>In this case, we can change a little bit our <code>deserialize</code> method to inspect fields of each PLAYER instance (looking for something unique by each instance).</p><figure class="kg-card kg-code-card"><pre><code class="language-java">  @Override
  public Player deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
      throws IOException {

    final ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
    final JsonNode playerNode = mapper.readTree(jsonParser);

    final SportType sportType = SportType.fromValue(playerNode.get("sportType").asText());

    if (playerNode.has("position")) {
      return mapper.treeToValue(playerNode, FootballPlayer.class);
    }
    if (playerNode.has("atpPoints")) {
      return mapper.treeToValue(playerNode, TennisPlayer.class);
    }
    log.warn("Unexpected Player type : {}", sportType.toString());
    throw new IllegalStateException("Unexpected Player type : " + sportType.toString());
  }</code></pre><figcaption>Deserialization logic based on fields of the Player abstract instances</figcaption></figure><h2 id="conclusion">Conclusion</h2><p>In this post, we learned how to handle, in the same endpoint, variable requests (polymorphism) in Jackson by using custom deserializer and without polluting our domain classes with annotations and external libraries.</p><h2 id="resources">Resources</h2><p>Source code : <a href="https://github.com/redamessoudi/polymorphic-deserialization">https://github.com/redamessoudi/polymorphic-deserialization</a></p><p>Header photo by <a href="https://unsplash.com/@eprouzet?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Eric Prouzet</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>]]></content:encoded></item><item><title><![CDATA[Receive emails with SubEtha SMTP and Spring Boot]]></title><description><![CDATA[<p>Some years ago I needed to write a Java application that receives emails and process some business stuff on those. It wasn't an easy task as I didn't find a lot of information. Because of that I decided, one day, I'll write about it and maybe that could helps 🙂.</p><h2 id="code-example">Code</h2>]]></description><link>https://redamessoudi.com/receive-emails-with-subetha-springboot/</link><guid isPermaLink="false">5ee79f3cc4d9800e39267ea9</guid><category><![CDATA[Java]]></category><dc:creator><![CDATA[Reda Messoudi]]></dc:creator><pubDate>Sat, 04 Jul 2020 14:15:42 GMT</pubDate><media:content url="https://redamessoudi.com/content/images/2020/07/liam-truong-YjWW9-VJlw4-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://redamessoudi.com/content/images/2020/07/liam-truong-YjWW9-VJlw4-unsplash.jpg" alt="Receive emails with SubEtha SMTP and Spring Boot"><p>Some years ago I needed to write a Java application that receives emails and process some business stuff on those. It wasn't an easy task as I didn't find a lot of information. Because of that I decided, one day, I'll write about it and maybe that could helps 🙂.</p><h2 id="code-example">Code example</h2><p>This post has a working code example available <a href="https://github.com/redamessoudi/subethasmtp-springboot">here</a>.</p><h2 id="context">Context</h2><h3 id="why">Why ?</h3><p>You would ask why do you need that ? I would say : </p><blockquote>Business requirements can surprise you every day</blockquote><p>Below a small list of some use cases when this incoming emails processing can be helpful.</p><ul><li>Testing : Can be good option for integration testing the email capabilities of your services/applications (The old <a href="http://nilhcem.com/FakeSMTP/">FakeSMTP</a> is a good GUI example)</li><li>Analyse received emails and extract some specific information</li><li>...</li></ul><h3 id="what">What ? </h3><p>SubEtha SMTP is low-level API for writing almost any kind of SMTP mail-receiving application.</p><p>To avoid you a long history presentation, the most updated version of SubEtha SMTP is a <a href="https://github.com/davidmoten/subethasmtp">fork</a> by <a href="https://davidmoten.github.io/">David Moten</a> (many thanks to him for his excellent work and keeping this library updated). We'll use this fork in this post.</p><p>I think no need to describe what's <a href="https://spring.io/projects/spring-boot">Spring Boot</a> in nowadays.</p><h2 id="let-s-code">Let's code</h2><p>Before starting the code, I suggest to see how we can send an email via terminal. We'll need that to send an email to our future emails receiver application. </p><h3 id="send-email-with-curl">Send email with cURL</h3><p>Below an example of sending email to specific mail server with parameters like <em>from</em>, <em>recipient</em>, <em>auth</em> and <em>the content</em> of the email.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">curl --url 'smtp://localhost:25000' \                                     
  --mail-from 'customer-address@mail.com' \
  --mail-rcpt 'info@marketing.company.com' \
  --user 'superus3r:passw0rd' \
  -T &lt;(echo -e 'From: customer-address@mail.com\nTo: info@marketing.company.com\nSubject: cURL Test\n\nHello, this is the content')</code></pre><figcaption>Send email with cURL</figcaption></figure><h3 id="subetha-dependency">SubEtha dependency</h3><p>Here we add the maven dependency of SubEtha SMTP.</p><figure class="kg-card kg-code-card"><pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.github.davidmoten&lt;/groupId&gt;
    &lt;artifactId&gt;subethasmtp&lt;/artifactId&gt;
    &lt;version&gt;5.2.4&lt;/version&gt;
&lt;/dependency&gt;</code></pre><figcaption><a href="https://mvnrepository.com/artifact/com.github.davidmoten/subethasmtp">SubEtha SMTP</a> maven dependency</figcaption></figure><h3 id="start-the-embedded-smtp-server">Start the embedded SMTP server</h3><p>It's very easy to start a simple SMTP server with the library. Just create/build an instance of SMTPServer with the right parameters like <em>port</em> and start this instance.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">// Build the embedded SMTP server
SMTPServer smtpServer = SMTPServer.port(25000).build();
// Start server asynchronously 
smtpServer.start();</code></pre><figcaption>Build and start SMTP server</figcaption></figure><p>Now our SMTP server is started but not fully ready to receive emails. We need to implement a MessageListener to extract important data like <em>from</em> and <em>recipient</em> addresses but also the <em>subject</em> and the <em>body</em> of the received email. </p><p>For that we can implement the <em>SimpleMessageListener</em><strong> </strong>interface :</p><figure class="kg-card kg-code-card"><pre><code class="language-java">public class MarketingMailListener implements SimpleMessageListener {

    private static final String MARKETING_DOMAIN = "@marketing.company.com";

    /**
     * Do some business logic here
     */
    @Override
    public boolean accept(String from, String recipient) {
        return recipient != null &amp;&amp; recipient.endsWith(MARKETING_DOMAIN);
    }

    @Override
    public void deliver(String from, String recipient, InputStream data) 
    throws TooMuchDataException, IOException {
        System.out.println("deliver message of MARKETING department");
        System.out.println("From : "+from);
        System.out.println("Recipient : "+recipient);
    }</code></pre><figcaption>Implement SimpleMessageListener interface</figcaption></figure><p>As you can see here, I added a simple business rule inside <em>accept</em> method to handle only emails sent to marketing department.</p><p>The <em>accept </em>method is responsible for defining if the received message will be proceeded by this listener or not.</p><p>The <em>deliver </em>method is responsible for extracting :</p><ul><li><em>From</em> : The sender address</li><li><em>Recipient</em> : The receiver address</li><li><em>Data</em> : It's an InputStream type from which we can extract content and relevant information related to the received email like : subject, body, CC, attachments and else.</li></ul><p>Let's see how we can extract the content of the email :</p><h3 id="convert-to-mimemessage">Convert to MimeMessage</h3><p>We can retrieve content from multipart content-typed message using <em>MimeMessage</em> instance.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">public MimeMessage convertToMimeMessage(InputStream data) 
throws MessagingException {
        Session session = Session.getDefaultInstance(new Properties());
        try {
            return new MimeMessage(session, data);
        }catch (MessagingException e){
            throw new MessagingException();
        }
    }</code></pre><figcaption>Convert InputStream to MimeMessage</figcaption></figure><h3 id="extract-email-content">Extract email content</h3><p>To extract the email content, we'll create an <em>ReceivedEmail</em> model to facilitate the processing.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">public class ReceivedEmail {

    private String subject;
    private String senderAddress;
    private String senderName;
    private String recipientAddress;
    private String recipientName;
    private String cc;
    private String bcc;
    private String contentType;
    private List&lt;DataSource&gt; attachments = new ArrayList();

    // Getters and setters
    // ...
}</code></pre><figcaption>ReceivedEmail model</figcaption></figure><p>For the sake of simplicity I used <em>String</em> for recipientAddress, CC and BCC but it's can be a list of addresses (example in the <a href="https://github.com/redamessoudi/subethasmtp-springboot">code</a>).</p><p>We create dedicated service for email content extraction and the <em>extract</em> method could looks like : </p><figure class="kg-card kg-code-card"><pre><code class="language-java">public ReceivedEmail extractReceivedEmail(InputStream data) throws Exception {
        ReceivedEmail receivedEmail = new ReceivedEmail();
        MimeMessage message;
        try {
            message = this.convertToMimeMessage(data);
            receivedEmail.setSubject(message.getSubject());
            receivedEmail.setSenderAddress(InternetAddress.toString(message.getFrom()));
            InternetAddress[] recipientAddresses = InternetAddress.parse(InternetAddress.toString(message.getAllRecipients()));
            receivedEmail.setRecipientAddress(InternetAddress.toString(recipientAddresses));
            receivedEmail.setRecipientName(recipientAddresses[0].getPersonal());
            receivedEmail.setContentType(message.getContentType());
            // Use here Apache library for parsing
            MimeMessageParser messageParser = new MimeMessageParser(message);
            messageParser.parse(); // very important to parse before getting data
            receivedEmail.setCc(messageParser.getCc().toString());
            receivedEmail.setBcc(messageParser.getBcc().toString());
            receivedEmail.setAttachments(messageParser.getAttachmentList());
            System.out.println(receivedEmail);
            return receivedEmail;
        } catch (Exception e) {
            throw new Exception();
        }
    }</code></pre><figcaption>Extract content of the received email</figcaption></figure><p>Now we have a full complete email receiver with minimal lines of code.</p><h3 id="secure-smtp-server">Secure SMTP Server</h3><p>Let's go further step to see how we can secure our mail server.</p><p>First thing to do is to indicate that the authentication is required and implement basic auth with username and password.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">this.smtpServer = SMTPServer
                .port(25000)
                .simpleMessageListener(marketingMsgListener)
                .requireAuth(true) // auth required
                .authenticationHandlerFactory(easyAuth) // implement type of auth
                .build();</code></pre><figcaption>Add authentication to the mail receiver server</figcaption></figure><p>Different implementations of <em>authenticationHandlerFactory</em> can be done, I chose here, again for the sake of simplicity, the <em>EasyAuthenticationHandlerFactory </em>class which needs implementation of the <em>UsernamePasswordValidator </em>interface.</p><figure class="kg-card kg-code-card"><pre><code class="language-java">@Configuration
public class SimpleAuthValidatorImpl implements UsernamePasswordValidator {

    private final String CREDENTIALS_LOGIN = "superus3r";
    private final String CREDENTIALS_PASSWORD = "passw0rd";

    @Override
    public void login(String username, String password, MessageContext context) throws LoginFailedException {
        if(CREDENTIALS_LOGIN.equals(username) &amp;&amp; CREDENTIALS_PASSWORD.equals(password)){
            System.out.println("Authenticated successfully");
        }else{
            System.err.println("Invalid authentication !");
            throw new LoginFailedException();
        }
    }
}</code></pre><figcaption>Add authentication to the mail receiver server</figcaption></figure><p>And this how our <em>SMTPServerConfig </em>looks like :</p><figure class="kg-card kg-code-card"><pre><code class="language-java">@Configuration
public class SMTPServerConfig {

    private final SMTPServer smtpServer;
    private final SimpleMessageListener marketingMsgListener;
    private final UsernamePasswordValidator authValidator;
    private final EasyAuthenticationHandlerFactory easyAuth;

    public SMTPServerConfig(SimpleMessageListener marketingMsgListener) {
        authValidator = new SimpleAuthValidatorImpl();
        easyAuth = new EasyAuthenticationHandlerFactory(authValidator);
        this.marketingMsgListener = marketingMsgListener;

        this.smtpServer = SMTPServer
                .port(25000)
                .simpleMessageListener(this.marketingMsgListener)
                .requireAuth(true)
                .authenticationHandlerFactory(easyAuth)
                .build();

        this.smtpServer.start();
    }
}</code></pre><figcaption>Custom configuration of SMTP server</figcaption></figure><h3 id="go-deeper">Go deeper</h3><p>More parameters can be customised to fit your needs and improve your SubEtha server, I list those below and you can try to explore them to improve your mail receiver implementation :</p><ul><li>Max connections and connection timeout</li><li>TLS support</li><li>Messages size</li><li>Shutdown of the SMTP server</li><li>Testing</li></ul><h2 id="conclusion">Conclusion</h2><p>I presented how we can, with small lines of code, write an application that can receive emails, handle those and apply some magic to them with SubEtha SMTP and Spring Boot.</p><p>If you have any questions or suggestions, please, leave your comments down below. </p><p>Thanks for reading and happy coding.</p><h2 id="resources">Resources</h2><p>Source code : <a href="https://github.com/redamessoudi/subethasmtp-springboot">https://github.com/redamessoudi/subethasmtp-springboot</a>.</p><p>Header photo by <a href="https://unsplash.com/@liamtruong?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Liam Truong</a> on <a href="https://unsplash.com/s/photos/mail?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>]]></content:encoded></item><item><title><![CDATA[Choreography vs. Orchestration for football fans]]></title><description><![CDATA[<p>Recently, I worked on a micro-services project which is cool thing but also challenging. Micro-services can solve many problems but also brings a panel of challenges.</p><p>Today we'll focus on <strong>micro-services communication</strong> challenge and for that we'll need a little bit knowledge of football and <em><a href="https://en.wikipedia.org/wiki/Ultras">Ultras</a> </em>world specially.</p><p>Spoiler : I'm</p>]]></description><link>https://redamessoudi.com/choreography-vs-orchestration-for-football-fans/</link><guid isPermaLink="false">5e63bcc3c4d9800e39267d8c</guid><category><![CDATA[Architecture]]></category><dc:creator><![CDATA[Reda Messoudi]]></dc:creator><pubDate>Fri, 19 Jun 2020 12:03:23 GMT</pubDate><media:content url="https://redamessoudi.com/content/images/2020/06/sergio-souza-eVbwuIvaR5g-unsplash-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://redamessoudi.com/content/images/2020/06/sergio-souza-eVbwuIvaR5g-unsplash-1.jpg" alt="Choreography vs. Orchestration for football fans"><p>Recently, I worked on a micro-services project which is cool thing but also challenging. Micro-services can solve many problems but also brings a panel of challenges.</p><p>Today we'll focus on <strong>micro-services communication</strong> challenge and for that we'll need a little bit knowledge of football and <em><a href="https://en.wikipedia.org/wiki/Ultras">Ultras</a> </em>world specially.</p><p>Spoiler : I'm a fan of <strong><a href="https://en.wikipedia.org/wiki/Wydad_AC">Wydad Athletic Club</a></strong>, a Moroccan sports club. </p><h2 id="-services-communication-challenge">µServices communication challenge</h2><p>If we build a micro-services architecture, in general we have at some point a communication between different/all services.</p><p>Those needs to communicate come with difficulties while the number of (<em>business</em>) services increase. We can imagine a simple business use case today can be chaotic in the future as business needs grows and changes.</p><p>In micro-services world and specifically communicating between different services, 2 main ways comes to mind : <strong>Choreography</strong> &amp;<strong> Orchestration</strong>.</p><p>On Internet, you can find most of the articles explaining this topic with the comparison between Dancers (<strong>Choreography</strong>) and Orchestra (<strong>Orchestration</strong>) which is good explanation, but let's try a different way.</p><h3 id="choreography-">CHOREOGRAPHY :</h3><p>Is <a href="https://en.wikipedia.org/wiki/Tifo"><em>Tifo</em></a> sounds familiar to you ? </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/06/tifo_choreography-winners_wydad.jpg" class="kg-image" alt="Choreography vs. Orchestration for football fans"><figcaption>Tifo by ultra <a href="https://www.facebook.com/UltraWinners2005/">Winners 2005</a> from Morocco</figcaption></figure><p>If not and in nutshell way, <em>Tifo</em> is a visual choreography performed by <em>ultra</em> using different materials. This <a href="https://youtu.be/lCXBYwsdrEI?t=324">performance</a> needs a lot of preparation by many persons but also a lot of collaboration and communication.</p><p>In a <em>Tifo</em> choreography, supporters are synchronized, move and accomplish their missions with no central task decider. Everything is prepared and repeated previously (days, months ago) .</p><p>Similar in µService world, perform a business process needs the involve of different services to be completed. The code is written, services deployed and ready to execute.</p><p>With choreography, every service is talking to another service with no <em>mediator</em> in the middle. Each service knows about the other. The business logic is <strong>distributed</strong>.</p><p>The workflow initiator service triggers the (<em>business</em>) flow by informing each service participant which will performs its tasks and informs other services.</p><p><strong>Pros</strong> : </p><ul><li>Distributed business logic with no centralized point</li><li>Decision logic managed by the service (= team)</li><li>Works well with agile delivery approach</li></ul><p><strong>Cons</strong> :</p><ul><li>Peer to peer event chains (excellent description <a href="https://youtu.be/r3f9nUw5I0g?t=505">here</a> by <a href="https://berndruecker.io/">Bernd Rücker</a>)</li><li>One service needs to subscribe to many events (is it healthy in a large scale architecture ? )</li><li>Complexity to change the flow of business processes (e.g It'll be complex to change the shopping flow : Delivery before payment)</li><li>Error handling can be a nightmare as each service (team) have the responsibility to understand how other services work and prevent cascading failure. </li></ul><h3 id="orchestration-">ORCHESTRATION : </h3><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://redamessoudi.com/content/images/2020/06/capo_orchestration-winners_wydad.jpg" class="kg-image" alt="Choreography vs. Orchestration for football fans"><figcaption>Ultra <a href="https://www.facebook.com/UltraWinners2005/photos/a.2766074176762246/2766086526761011/?type=3&amp;theater">Winners 2005</a></figcaption></figure><p>Did you see this man in the middle surrounded by a lot of supporters ? This is the <em>Capo </em>in football and <em>ultras </em>jargon.</p><p><em>Capo </em>means "head" in Italian. He is the representative leader of a group of <em>ultras </em>supporters. As you can see in the image, his back to the game and his face to supporters to lead them in terms of <a href="https://www.youtube.com/watch?v=5jGbuIozvco&amp;t=147">chants and movements</a> (Headphones and low volume highly recommended).</p><blockquote>Capo is the guarantor of the show</blockquote><p>Yes, you're right if you guessed that <em>Capo </em>is Orchestrator in Orchestrated µService architecture.</p><p>Orchestration is driven by a central system (the Orchestrator in general) which is the responsible to determine what to do, when and by who in order to guide and control a business workflow/process, which is very similar to the <em>Capo </em>who controls the movements and chants of supporters.</p><p>Supporters = Workers in orchestrated architecture and workers are – generally– your business services (e.g shipment, delivery, payment). </p><p>Each worker performs its tasks and informs the Orchestrator by returning the result. The Orchestrator takes decisions for the next steps.</p><p><strong>Pros</strong> :</p><ul><li>Flexibility : Easy to change and evolve the business workflows and processes</li><li><a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> : The workflow logic is on the same place </li><li>Clear monitoring of your processes progress</li></ul><p><strong>Cons</strong> :</p><ul><li>The workflow engine becomes a central piece of the architecture and could be <a href="https://en.wikipedia.org/wiki/Single_point_of_failure">SPoF</a></li><li>As its very important component, the orchestrator could become more proprietary than the business itself in terms of operations specially with a decentralized approach.</li></ul><h2 id="conclusion">Conclusion</h2><p>Both of architectures are valid but the choice depends on the complexity of your µService world. </p><p>For a small/medium systems with moderated complexity, I would say go for <strong>Choreography</strong> but if the number of events is large or can increase in the near future, it'll become more and more complex to handle the code and logic in individual services. Whereas <strong>Orchestration</strong> can be more elegant in handling multiple events with less confusion.</p><p>For sure you can mix the both architectures – as <em>Ultras</em> do to support their clubs while spending a lot of time, effort and engagement to have such impressive results – but don't push your luck.</p><h2 id="resources">Resources</h2><p>Header photo by <a href="https://unsplash.com/@serjosoza?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">sergio souza</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>]]></content:encoded></item></channel></rss>