<?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: Victor Gallet</title>
    <description>The latest articles on DEV Community by Victor Gallet (@vga).</description>
    <link>https://dev.to/vga</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%2F55647%2Fd46ce1cd-c689-4a67-8e0c-b35483f9e38c.jpg</url>
      <title>DEV Community: Victor Gallet</title>
      <link>https://dev.to/vga</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vga"/>
    <language>en</language>
    <item>
      <title>Why you should stop doing code reviews!</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Wed, 03 Jan 2024 13:32:00 +0000</pubDate>
      <link>https://dev.to/manomano-tech-team/why-you-should-stop-doing-code-reviews-lme</link>
      <guid>https://dev.to/manomano-tech-team/why-you-should-stop-doing-code-reviews-lme</guid>
      <description>&lt;p&gt;&lt;em&gt;I would like to thank Baptiste Barbieri, Antoine Guy, Maxence Zajdlic and Rafael S. Ward for their time &amp;lt;3.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Code review is one of the most used methods in software development. We all know what are the benefits of doing code review.&lt;/p&gt;

&lt;p&gt;To sum up, doing code review enables verification of new code quality by identifying future bugs, ensuring tested code, and ensuring readable code.&lt;/p&gt;

&lt;p&gt;Moreover, by reading code written by others, developers can learn from others. A junior developer can learn by reading the code of a more experienced one. They can ask questions using comments.&lt;br&gt;
Vice versa a senior developer can check the code of a junior developer and provide constructive feedback.&lt;/p&gt;

&lt;p&gt;I won’t go deeper into code review benefits in this article. For more information, you can read the amazing work done by Trisha Gee. For instance &lt;a href="https://trishagee.github.io/post/code_review_best_practices/"&gt;this blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, is code review really worth doing? What are the drawbacks we faced doing code review? I tried to list all code review antipatterns I faced and I’m sure you faced some of them. Several times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code review pitfalls
&lt;/h2&gt;

&lt;h4&gt;
  
  
  The “ping pong” review
&lt;/h4&gt;

&lt;p&gt;Some comments are added, you take them into account, some new comments are added, you take them into account, new comments are added…and so on. It’s really frustrating for the merge request author, even more when it happens with several reviewers.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “re-design” review
&lt;/h4&gt;

&lt;p&gt;Once the merge request opens, you receive comments indicating a large design issue. It’s not a simple correction, but the whole implementation must be redone. This is a demoralizing situation for the author and the reviewers and a waste of time.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “ghosting” review
&lt;/h4&gt;

&lt;p&gt;Comments are added, taken into account and then you wait for the approval. The reviewer has disappeared and you have to wait before merging. Even if other reviewers have approved the merge request, you have to wait for the ghost reviewer.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “waiting for” review
&lt;/h4&gt;

&lt;p&gt;Your merge request is not the most attractive and you are still awaiting approval.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “TL;DR” review
&lt;/h4&gt;

&lt;p&gt;Changes are very important but reviewers didn’t read it before approving it because it was too long.&lt;/p&gt;

&lt;h4&gt;
  
  
  The presentation review
&lt;/h4&gt;

&lt;p&gt;You have done a huge refactoring or the changes you bring are really complex to review and your team is asking you for a presentation or a mob review. Now you have to find a time where everyone is available to do the code review, it’s only the beginning of your merge request journey.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “convention style” review
&lt;/h4&gt;

&lt;p&gt;Some comments on the merge request are merely about coding style. For instance, there are too many break lines or spaces. Those kinds of reviews could be avoided with a linter.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “too small” merge request
&lt;/h4&gt;

&lt;p&gt;If one line of code has been modified, you tend to think that it will be approved and merged fast. BUT! Instead, it triggers a lot of discussions. We are typically in a &lt;a href="https://en.wikipedia.org/wiki/Law_of_triviality"&gt;bike-shed effect&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “keep rebasing” review
&lt;/h4&gt;

&lt;p&gt;Your merge request is waiting for approval, while other merge requests are merged and you have to keep your code up to date and potentially resolve conflicts.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “inconsistent feedback” review
&lt;/h4&gt;

&lt;p&gt;Sometimes you get a comment and don’t know how to handle it. Most of the time, the review expressed a feeling more than a clear solution. For example “This function seems too complicated for me”.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “after merged” review
&lt;/h4&gt;

&lt;p&gt;The merge request has been approved and merged. Great! But a new challenger has appeared! This challenger is perhaps knowledgeable about the project or on the technologies used and he wants to make some changes. Most of the time, a new merge request will be opened by this person without sharing it with the first developer.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “conflict” review
&lt;/h4&gt;

&lt;p&gt;Expressing or receiving feedback can be complicated, people can take it personally and it can lead to some tensions in the team.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “elderly” merge request
&lt;/h4&gt;

&lt;p&gt;The merge request is open for a long time, it could be a couple of weeks, a month or even a year. The merge request is so old that most of the developers don’t know if it’s still relevant to merge it so the merge request will just sit there.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “not working” review
&lt;/h4&gt;

&lt;p&gt;The CI pipeline passed, and the merge request has been approved but once merged and deployed... it doesn’t work! Let’s do a full cycle again.&lt;/p&gt;

&lt;h4&gt;
  
  
  The “Full-time job” review
&lt;/h4&gt;

&lt;p&gt;Code review can be a full-time job! A developer in a team could spend their entire time doing code review. Furthermore, it’s not uncommon to have developers in a team who are spending way more time than others doing code reviews. Not everyone does code review in a balanced way and it can lead to struggles within the team.&lt;/p&gt;

&lt;p&gt;The worst thing about all those patterns is that they can be accumulated. You can be in a ping pong review, suddenly land on with a ghost review, keep rebasing and finish by having some tensions in your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop doing code review?
&lt;/h2&gt;

&lt;p&gt;So what are the solutions to avoid those situations? Most of these problems could be avoided by sharing early. Before what?&lt;br&gt;
For instance, sharing about coding guidelines, architecture, coding practices or design before jumping into the code. All of these methods and practices are living, moving with time and have to be updated during the project lifecycle.&lt;/p&gt;

&lt;p&gt;It’s merely an Agile value: having feedback as soon as possible. Feedback coming from code review is too late.&lt;/p&gt;

&lt;p&gt;In my experience, code review creates more problems than it solves. Code review is only good when developers work mostly in an asynchronous way and in different time zones. But in most cases, developers are working in the same team, on the same project at the same time and code review is only a way to avoid exchanges with colleagues. Nowadays, code review is a cargo cult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most of the time&lt;/strong&gt; code review should be replaced by pair programming or better still ensemble programming (also known as mob programming).&lt;br&gt;
In that way, you have at least two people working on the same piece of code and you always have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;knowledge sharing, both business and technical knowledge&lt;/li&gt;
&lt;li&gt;proof-reading&lt;/li&gt;
&lt;li&gt;developing cohesion and team spirit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing pair programming, doing synchronous development saves from ghosting, from ping pong comments, “TL;DR” review, “waiting for” review, “convention style” review….and so on. Actually, working together avoids all of the pitfalls of code review.&lt;/p&gt;

&lt;p&gt;If you are developing using TDD, pair programming can even be more fun by doing &lt;a href="https://anthonysciamanna.com/2015/04/18/ping-pong-pair-programming.html"&gt;ping pong pair programming&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, I won’t debate about the simplistic idea that having two developers working together on the same task is more expensive compared to having them working alone. The synchronisation process in all steps is one of the most expensive and code review is one of them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://vgallet.github.io"&gt;https://vgallet.github.io&lt;/a&gt; on December 14, 2023.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
      <category>development</category>
    </item>
    <item>
      <title>Some cool features you may not know about Apache Kafka</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Fri, 18 Jun 2021 08:10:44 +0000</pubDate>
      <link>https://dev.to/vga/some-cool-features-you-may-don-t-know-about-apache-kafka-4768</link>
      <guid>https://dev.to/vga/some-cool-features-you-may-don-t-know-about-apache-kafka-4768</guid>
      <description>&lt;p&gt;Apache Kafka is a widely distributed event streaming platform. In this article, I won’t explain Apache Kafka fundamentals like what’s a topic, a partition, an offset nor In-Sync Replicas. You can find a lot of resources to learn how Apache Kafka works and its fundamentals. I will present to you some features you may not have heard about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metric Reporters
&lt;/h2&gt;

&lt;p&gt;You may already know that Apache Kafka Clients: Producer and Consumer, can be monitored using JMX metrics. You can browse all the JMX metrics exposed for a Consumer &lt;a href="https://kafka.apache.org/documentation/#consumer_monitoring" rel="noopener noreferrer"&gt;here&lt;/a&gt; and for a Producer &lt;a href="https://kafka.apache.org/documentation/#producer_monitoring" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By default, Apache Kafka Clients exposed the JMX Metrics using the class &lt;a href="https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/metrics/JmxReporter.java" rel="noopener noreferrer"&gt;JmxReporter&lt;/a&gt;. This class implements the interface &lt;a href="https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/metrics/MetricsReporter.java" rel="noopener noreferrer"&gt;MetricsReporter&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MetricsReporter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reconfigurable&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AutoCloseable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&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;KafkaMetric&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;metricChange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KafkaMetric&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;metricRemoval&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KafkaMetric&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reconfigurableConfigs&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emptySet&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validateReconfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configs&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;ConfigException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;reconfigure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configs&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;@Evolving&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;contextChange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MetricsContext&lt;/span&gt; &lt;span class="n"&gt;metricsContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And so you can define your own way to expose those Kafka Metrics by implementing this interface and setting the configuration &lt;a href="https://kafka.apache.org/documentation/#producerconfigs_metric.reporters" rel="noopener noreferrer"&gt;&lt;code&gt;metric.reporters&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;METRIC_REPORTER_CLASSES_CONFIG&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyMetricReporter&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Client Interceptor
&lt;/h2&gt;

&lt;p&gt;Client Interceptor lets you intercept received or produced records and possibly mutate them. For each Apache Kafka Clients: Producer and Consumer, you can define interceptor classes.&lt;/p&gt;

&lt;p&gt;For the producer, you have to implement the interface &lt;code&gt;ProducerInterceptor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ProducerInterceptor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Configurable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ProducerRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onSend&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProducerRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onAcknowledgement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RecordMetadata&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;close&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;For the consumer, it’s the interface &lt;code&gt;ConsumerInterceptor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ConsumerInterceptor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Configurable&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AutoCloseable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ConsumerRecords&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onConsume&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerRecords&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onCommit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TopicPartition&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OffsetAndMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;partitions&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;close&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;Once you have implemented those interfaces, add your interceptors to the client using the configuration &lt;code&gt;interceptor.classes&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INTERCEPTOR_CLASSES_CONFIG&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyConsumerInterceptor&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly useful if you use Apache Kafka in a microservices architecture and you want to add tracing supervision. For example, using OpenTracing you can take a look at &lt;a href="https://github.com/opentracing-contrib/java-kafka-client" rel="noopener noreferrer"&gt;opentracing-contrib/java-kafka-client&lt;/a&gt; that provides &lt;code&gt;TracingProducerInterceptor&lt;/code&gt; and &lt;code&gt;TracingConsumerInterceptor&lt;/code&gt;. Those interceptors inject and retrieve span context from record headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partition Assignment &amp;amp; Co-partitioning
&lt;/h2&gt;

&lt;p&gt;Let’s say you have 10 topics, each topic has 1 partition and you create a consumer group with 10 consumer instances. How will the consumers assign each partition? You may suppose that one consumer consumes one partition...In fact, it depends on the strategy used to assign the partitions amongst the consumer instances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By default&lt;/strong&gt;, the consumers are configured to use the &lt;a href="https://kafka.apache.org/27/javadoc/org/apache/kafka/clients/consumer/RangeAssignor.html" rel="noopener noreferrer"&gt;&lt;code&gt;RangeAssignor&lt;/code&gt;&lt;/a&gt;. This strategy’s goal is to co-localized the partitions of each subscribed topic to the same consumer. And so, to answer the first question, one consumer will be assigned to all the partitions and the other consumers remaining will be idle.&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%2F28gkio6bfndnftraeq7q.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%2F28gkio6bfndnftraeq7q.png" alt="RangeAssignor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This strategy used by default is designed to be used with &lt;strong&gt;co-partitioning topics&lt;/strong&gt;. Co-partitioning topics are topics with the same number of partitions and where messages are produced with the same partitioner and the same partitioning key.&lt;br&gt;
However, if your goal is to maximize the number of consumers used in your consumer group, you should change the default assignment strategy using the property &lt;code&gt;partition.assignment.strategy&lt;/code&gt; to use the &lt;a href="https://kafka.apache.org/27/javadoc/org/apache/kafka/clients/consumer/RoundRobinAssignor.html" rel="noopener noreferrer"&gt;&lt;code&gt;RoundRobinAssignor&lt;/code&gt;&lt;/a&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%2F69109kmcg17r5d6fs3rz.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%2F69109kmcg17r5d6fs3rz.png" alt="RangeAssignor"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rack Awareness
&lt;/h2&gt;

&lt;p&gt;By specifying the property &lt;code&gt;broker.rack&lt;/code&gt; on each broker of the cluster, Apache Kafka will spread replicas of the same partition across all the specified racks. This feature limits the risk of data loss if a rack goes down. A rack can be a cloud provider zone or a data center location.&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%2Fcuiifouowd7yjg3j1bxh.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%2Fcuiifouowd7yjg3j1bxh.png" alt="Apache Kafka Rack Awareness"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, Apache Kafka clients always interact with the partition leader, so it can be a problem if your clients are located in a different zone from the broker leader.&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%2F7cbmskq1e8utj9bv7w8g.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%2F7cbmskq1e8utj9bv7w8g.png" alt="Apache Kafka Client Rack Awareness"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this diagram, the consumer is located in zone-B, and the partition leader is located in zone-A. It increases the number of cross-zone requests and can increase the billing at some cloud providers.&lt;br&gt;
To avoid this issue, Apache Kafka 2.4 introduces the notion of Follower-Fetching. It means that a consumer can fetch data directly from a follower instead of from the partition leader. To enable this feature, brokers have to set the property &lt;code&gt;broker.rack&lt;/code&gt; with the desired location and &lt;code&gt;replica.selector.class&lt;/code&gt; with &lt;code&gt;org.apache.kafka.common.replica.RackAwareReplicaSelector&lt;/code&gt;. On the other hand, Consumers have to set &lt;code&gt;client.rack&lt;/code&gt; to tell in which location they are.&lt;/p&gt;
&lt;h2&gt;
  
  
  Kafka Lag Exporter
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/lightbend/kafka-lag-exporter" rel="noopener noreferrer"&gt;Kafka Lag Exporter&lt;/a&gt; is not part of the Apache Kafka project nor the Confluent Platform. It’s an open-source project under Apache-2.0 License to export Consumer Lag with reporters like Prometheus, Graphite, or InfluxDB. Kafka Lag Exporter enables to monitor Consumer Lag but it also allows to estimate the Time Lag. This metric shows how far a Consumer group is behind the last produced record in terms of time. It shows the actual latency of a consumer application. For more information about this estimation, you can read the chapter of the documentation &lt;a href="https://github.com/lightbend/kafka-lag-exporter#estimate-consumer-group-time-lag" rel="noopener noreferrer"&gt;Estimate Consumer Group Time Lag&lt;/a&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%2F7o9roqh4b0k2cfez6i3o.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%2F7o9roqh4b0k2cfez6i3o.png" alt="KLE Time Lag interpolation"&gt;&lt;/a&gt;&lt;br&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%2Fz0vb7n1tgd32is11hugo.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%2Fz0vb7n1tgd32is11hugo.png" alt="KLE Time Lag extraplocation"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Cluster Linking
&lt;/h2&gt;

&lt;p&gt;In a Multi Data Center architecture, Cluster Linking is the ability to create a link between two distincts Apache Kafka clusters. Once the link is established, you are able to mirror topics.&lt;br&gt;
Mirroring a topic means that all the data from a topic and its configuration in the source cluster is replicated to a topic with the same name in the destination cluster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unlike, Replicator and MirrorMaker2, Cluster Linking does not require running Connect to move messages from one cluster to another, ensuring that the offsets are preserved from one cluster to another. We call this “byte-for-byte” replication. Whatever is on the source, will be mirrored precisely on the destination cluster.&lt;br&gt;
&lt;a href="https://docs.confluent.io/platform/current/multi-dc-deployments/cluster-linking/index.html" rel="noopener noreferrer"&gt;https://docs.confluent.io/platform/current/multi-dc-deployments/cluster-linking/index.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The destination topic does a “byte-for-byte” replication, it preserves the offsets from one cluster to another and it also replicates source topic configuration like retention, number of partitions from the source topic.&lt;/p&gt;

&lt;p&gt;Cluster Linking is a really promising feature but it’s currently &lt;strong&gt;a preview feature&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A preview feature is a component of the Confluent Platform that is being introduced to gain early feedback from developers. This feature can be used for evaluation and non-production testing purposes or to provide feedback to Confluent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Confluent provides &lt;a href="https://github.com/confluentinc/demo-scene/tree/master/cluster-linking" rel="noopener noreferrer"&gt;a demonstration project&lt;/a&gt; to play with this feature.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tiered Storage
&lt;/h2&gt;

&lt;p&gt;Tiered Storage is the ability to store the data into external storage instead of the local disk of your brokers. The idea is to separate the concerns of data storage from the concerns of data processing. It allows you to retain your data for months, years, or indefinitely.&lt;/p&gt;

&lt;p&gt;You can configure your Apache Kafka cluster with one of the three supported tiered storage: AWS S3, GCP GCS, and Pure Storage FlashBlade.&lt;/p&gt;

&lt;p&gt;For example with Amazon S3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;confluent.tier.feature=true
confluent.tier.enable=true
confluent.tier.backend=S3
confluent.tier.s3.bucket=&amp;lt;BUCKET_NAME&amp;gt;
confluent.tier.s3.region=&amp;lt;REGION&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you can create a topic with tiered storage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kafka-topics --bootstrap-server localhost:9092   \
  --create --topic tiered-storage-topic \
  --partitions 6 \
  --replication-factor 3 \
  --config confluent.tier.enable=true \
  --config confluent.tier.local.hotset.ms=3600000 \
  --config retention.ms=604800000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;retention.ms&lt;/code&gt; works the same as a normal topic. It defines the time you want to keep your data in the local storage or in the tiered storage.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;confluent.tier.local.hotset.ms&lt;/code&gt; defines the time in milliseconds a non-active segment is retained on the local storage. Once it’s expired, the segment is deleted from the local storage and saved to the tiered storage.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.confluent.io/platform/current/kafka/post-deployment.html#balancing-replicas-across-racks" rel="noopener noreferrer"&gt;https://docs.confluent.io/platform/current/kafka/post-deployment.html#balancing-replicas-across-racks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.confluent.io/platform/current/multi-dc-deployments/cluster-linking/index.html" rel="noopener noreferrer"&gt;https://docs.confluent.io/platform/current/multi-dc-deployments/cluster-linking/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.confluent.io/platform/current/multi-dc-deployments/multi-region.html#follower-fetching" rel="noopener noreferrer"&gt;https://docs.confluent.io/platform/current/multi-dc-deployments/multi-region.html#follower-fetching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lightbend/kafka-lag-exporter#estimate-consumer-group-time-lag" rel="noopener noreferrer"&gt;https://github.com/lightbend/kafka-lag-exporter#estimate-consumer-group-time-lag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.confluent.io/platform/current/multi-dc-deployments/cluster-linking/tutorial.html" rel="noopener noreferrer"&gt;https://docs.confluent.io/platform/current/multi-dc-deployments/cluster-linking/tutorial.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.confluent.io/platform/current/kafka/tiered-storage.html" rel="noopener noreferrer"&gt;https://docs.confluent.io/platform/current/kafka/tiered-storage.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>apachekafka</category>
      <category>kafka</category>
    </item>
    <item>
      <title>The day I erased all the customer data</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Sat, 23 May 2020 15:37:25 +0000</pubDate>
      <link>https://dev.to/zenika/the-day-i-erased-all-the-customer-data-55f5</link>
      <guid>https://dev.to/zenika/the-day-i-erased-all-the-customer-data-55f5</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by Sarah Kilian on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This story takes place in a company where I previously worked. Back then, I was a young developer and I was tasked with the deletion of former customer’s data.&lt;/p&gt;

&lt;p&gt;I checked the database and identified all the tables that would be impacted. Then, I wrote a SQL script to delete all the rows concerning this particular customer. &lt;br&gt;
This script was not directly executed in the production environment. Instead, all changes are included in a version control system tool equivalent to Liquibase or Flyway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J-PjDWLX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.giphy.com/media/CzbiCJTYOzHTW/giphy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J-PjDWLX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.giphy.com/media/CzbiCJTYOzHTW/giphy.webp" alt="done"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few days later, our support team received a phone call from a customer who could no longer find his data on the application. After performing an investigation, we came to the realization that all customer data were deleted from the database. The main culprit was none other than my SQL script. Indeed, some &lt;code&gt;DELETE&lt;/code&gt; SQL statements were missing the &lt;code&gt;WHERE&lt;/code&gt; clause. In the meantime, the ops team tried to restore the production database with the most recent backup.&lt;/p&gt;

&lt;p&gt;At that time, I was petrified and I dreaded what my boss could say to me. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tRgBpEKK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.giphy.com/media/zdFNkQ6vGJADC/giphy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tRgBpEKK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.giphy.com/media/zdFNkQ6vGJADC/giphy.webp" alt="petrified"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To my surprise, he did not single me out but blamed all the team and particularly our quality checks. In fact, he simply wanted to answer this question: How could this blunder have made its way to the production environment?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SMAMA7fy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.giphy.com/media/3o7aTskHEUdgCQAXde/giphy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SMAMA7fy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.giphy.com/media/3o7aTskHEUdgCQAXde/giphy.webp" alt="done"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First of all, the SQL script was merged on the master branch, with at least 2 approbators on my pull request. So, it means that our code review was not thorough enough. &lt;br&gt;
Secondly, this script passed all our End to End tests and manual testing. &lt;br&gt;
Finally, we discovered that the database backup system was not working properly and the last available backup was at least 2 months old. Luckily, it had a fairly limited impact on our business, since it happened during summertime. &lt;/p&gt;

&lt;p&gt;In my opinion, we can learn two things about this little story. In the first place, a good team and a good manager will not put the blame on you if you have done a mistake. Everyone makes mistakes and it’s a good way to question some of the practices.&lt;br&gt;
In the second place, it is important for a team to insure itself against the risk of fault, error or minor oversight. Despite quality processes, it’s important to test and prove those processes. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Marc Barret for his time and his review&lt;/em&gt;&lt;/p&gt;

</description>
      <category>blunder</category>
      <category>learning</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Workshop Azure Pipelines</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Fri, 24 Apr 2020 09:34:19 +0000</pubDate>
      <link>https://dev.to/zenika/workshop-azure-pipelines-3mc0</link>
      <guid>https://dev.to/zenika/workshop-azure-pipelines-3mc0</guid>
      <description>&lt;p&gt;I have been working with &lt;a href="https://azure.microsoft.com/fr-fr/services/devops/pipelines/"&gt;Azure Pipelines&lt;/a&gt; for some time and I would like to introduce it to you. Instead of describing it into a blog post, I made an online workshop to manipulate it.&lt;/p&gt;

&lt;p&gt;During this workshop, you will learn how to set up a CI pipeline to build a Maven / Java application and a NodeJs application. You will also discover Azure Pipelines features, such as pipeline caching, variables, parameters, and templating.&lt;br&gt;
If you would like to take this workshop, all you need is a Github account.&lt;/p&gt;

&lt;p&gt;Please feel free to send me feedback here on the comment section or by creating a Github issue to &lt;a href="https://github.com/vgallet/workshop-azure-pipelines"&gt;the project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the link &lt;a href="https://workshop-azure-pipelines.netlify.app/"&gt;https://workshop-azure-pipelines.netlify.app/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ci</category>
      <category>devops</category>
      <category>azure</category>
      <category>pipeline</category>
    </item>
    <item>
      <title>Add chaos in your network!</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Wed, 11 Dec 2019 19:34:13 +0000</pubDate>
      <link>https://dev.to/zenika/add-chaos-in-your-network-4i4d</link>
      <guid>https://dev.to/zenika/add-chaos-in-your-network-4i4d</guid>
      <description>&lt;p&gt;An important rule in production is to never trust your network! There will always be problems and Netflix has clearly understood this statement by creating &lt;a href="https://en.wikipedia.org/wiki/Chaos_engineering#Chaos_Monkey"&gt;Chaos Monkey&lt;/a&gt; in 2011.&lt;br&gt;
In this article, we will focus on chaos in the network. For example to assert that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an application is resilient to network latency&lt;/li&gt;
&lt;li&gt;a website still offers a comfortable experience despite a limited bandwidth&lt;/li&gt;
&lt;li&gt;a distributed system cannot go into split-brain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;tc&lt;/code&gt; is a Linux command to manage network traffic. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc add dev eth0 root netem delay 200ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This command add 200 milliseconds latency on the network of eth0 interface. Let’s dissect it.&lt;/p&gt;

&lt;p&gt;As quoted from &lt;a href="http://man7.org/linux/man-pages/man8/tc.8.html"&gt;linux man page&lt;/a&gt;, &lt;code&gt;qdisc&lt;/code&gt; is &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;short for 'queueing discipline' and it is elementary to understanding traffic control.&lt;br&gt;
Whenever the kernel needs to send a packet to an interface, it is enqueued to the qdisc configured for that interface.&lt;br&gt;
Immediately afterwards, the kernel tries to get as many packets as possible from the qdisc, for giving them to the network adaptor driver.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;add&lt;/code&gt; is to add a new rule.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dev eth0&lt;/code&gt; means the rule is applied to the device, the network interface eth0.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;root&lt;/code&gt; is the class attached to the network packet. In this case, the rule is applied to all packets.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;netem&lt;/code&gt; means Network Emulator. It’s the tool to add a behaviour.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;delay 200ms&lt;/code&gt; is the rule to apply. Here it’s a 200 milliseconds latency.&lt;/p&gt;

&lt;p&gt;Once the rule is applied, we can list all the rules applied to eth0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc show dev eth0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And to delete it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc del dev eth0 root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the first example, the latency impacts the whole network, including a ssh connection. In order to not impact all the network but only a port, an IP or a range of IP, it’s possible to use the class concept of qdisc.&lt;br&gt;
By default, a qdisc is divided into 3 bands: 0, 1 et 2. This command helps to see these bands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc ls

qdisc noqueue 0: dev lo root refcnt 2 
qdisc pfifo_fast 0: dev eth0 root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev eth1 root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On my computer, eth0 has 3 bands with a priority map of &lt;code&gt;1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1&lt;/code&gt;.&lt;br&gt;
The band used is determined by network packet &lt;a href="https://en.wikipedia.org/wiki/Type_of_service"&gt;TOS&lt;/a&gt;. TOS stands for Type Of Service. This is simply four bits indicating the type of priority.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Binary Decimal  Meaning
-----------------------------------------
1000   8         Minimize delay (md)
0100   4         Maximize throughput (mt)
0010   2         Maximize reliability (mr)
0001   1         Minimize monetary cost (mmc)
0000   0         Normal Service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here’s the table used to determine the band. There is more explanation of how it works directly on &lt;a href="https://www.systutorials.com/docs/linux/man/8-tc-prio/"&gt;the man page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First of all, a rule is added to change the priority map. All the traffic will go to the first band.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc add dev eth0 root handle 1: prio priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, this rule defines the behaviour added but only on the third band. Here it’s a delay of 1000 milliseconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc add dev eth0 parent 1:2 handle 20: netem delay 1000ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, a filter is applied to redirect all the traffic matching a destination IP to the third band. To ensure it works correctly, a simple ping to that IP does the trick.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc filter add dev eth0 parent 1:0 protocol ip u32 match ip dst &amp;lt;mon ip&amp;gt; flowid 1:2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;64 bytes from &amp;lt;server&amp;gt; (&amp;lt;mon ip&amp;gt;): icmp_seq=143 ttl=62 time=1000 ms
64 bytes from &amp;lt;server&amp;gt; (&amp;lt;mon ip&amp;gt;): icmp_seq=144 ttl=62 time=1000 ms
64 bytes from &amp;lt;server&amp;gt; (&amp;lt;mon ip&amp;gt;): icmp_seq=145 ttl=62 time=1000 ms
64 bytes from &amp;lt;server&amp;gt; (&amp;lt;mon ip&amp;gt;): icmp_seq=146 ttl=62 time=1000 ms
64 bytes from &amp;lt;server&amp;gt; (&amp;lt;mon ip&amp;gt;): icmp_seq=147 ttl=62 time=1001 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The rule is correctly applied. Here it’s using a filter on an IP but it works with a subnet mask and/or a port. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst &amp;lt;mon IP&amp;gt; match ip dport &amp;lt;mon port&amp;gt; 0xffff flowid 1:2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Other options
&lt;/h3&gt;

&lt;p&gt;Here some other possibilities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netem delay 100ms 10ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;this rule adds 100 milliseconds of delay plus or less 10 milliseconds in an uniform disribution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netem loss 10%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;10% of packets are loss.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netem duplicate 50%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;50% of packets are duplicated&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netem corrupt 5%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;5% of packets are corrupt.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limit bandwidth
&lt;/h3&gt;

&lt;p&gt;Finally, the tool Token Bucket Filter (TBF) enables to limit the &lt;strong&gt;outgoing&lt;/strong&gt; bandwidth.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tbf rate 20kbit buffer 1600 limit 3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The outgoing bandwidth is limited to 20 kilobits.&lt;/p&gt;

&lt;p&gt;A big thanks to Marc Barret for his time and proofreading.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by American Public Power Association on Unsplash&lt;/em&gt;&lt;/p&gt;

</description>
      <category>network</category>
      <category>linux</category>
      <category>latency</category>
      <category>chaos</category>
    </item>
    <item>
      <title>PostgreSQL Replication</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Tue, 10 Dec 2019 20:09:16 +0000</pubDate>
      <link>https://dev.to/zenika/postgresql-replication-3423</link>
      <guid>https://dev.to/zenika/postgresql-replication-3423</guid>
      <description>&lt;p&gt;There are plenty of tutorials available online, which give step-by-step instructions to manage the replication of PostgreSQL clusters with Repmgr. Once the setup is complete, what is important to look for? How does your client handle failover? How to deal with a failed or unreachable standby node? How to reintegrate a failed or unreachable standby node? How do you monitor your cluster?&lt;/p&gt;

&lt;h2&gt;
  
  
  Client Failover
&lt;/h2&gt;

&lt;p&gt;When your primary node goes down and a standby is promoted. How do you let your clients handle this change?&lt;/p&gt;

&lt;h3&gt;
  
  
  Official driver
&lt;/h3&gt;

&lt;p&gt;A simple solution is to use official driver capabilities. As mentioned in the &lt;a href="https://jdbc.postgresql.org/documentation/head/connect.html"&gt;documentation&lt;/a&gt;, you can list all nodes in your cluster and the connection will be established only on the primary node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdbc:postgresql://primary,standby1,standby2/database?targetServerType=master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this situation, the primary node will handle all the read and write queries. However, it’s possible to create a second connection dedicated to read queries on standby nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdbc:postgresql://primary,standby1,standby2/database?targetServerType=preferSlave
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Handmade solution
&lt;/h3&gt;

&lt;p&gt;It’s possible to create your own solution to enable connection failover. For example in &lt;a href="https://www.percona.com/blog/2019/10/31/postgresql-application-connection-failover-using-haproxy-with-xinetd/"&gt;this article&lt;/a&gt;, a shell script is used to check PostgreSQL status and HAProxy is used to perform failover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repmgrd
&lt;/h2&gt;

&lt;p&gt;Repmgrd is the Repmgr daemon. It monitors the PostgreSQL cluster and performs necessary actions based on the state of the cluster. It performs automatic failover in the case that the primary node goes down by promoting the most eligible standby as the new primary.&lt;/p&gt;

&lt;p&gt;Repmgrd is a critical process that should be running at all times. The failover mechanism would not be able to kick in if it were to stop working.&lt;br&gt;
Therefore, it is highly recommended to enable “auto restart” by overriding the provided daemon’s configuration file with systemd.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.include /lib/systemd/system/repmgr.service
[Service]
Restart=always
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this configuration, the daemon will be restarted in case of failure after a timeout of 10 seconds. It will try 3 times during an interval of 60 seconds. In any case, if Repmgr daemon is going down, it means there is a problem with the service or on the server and simply restarting the service may not fix the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promotion
&lt;/h3&gt;

&lt;p&gt;Promoting a new primary is one of the most important actions during a failover situation. Repmgr knows when by doing reconnect attempts. Depending on the quality of your network, you may need to avoid promotion caused by network latency by modifying &lt;code&gt;reconect_attempts&lt;/code&gt; and &lt;code&gt;reconnect_interval&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Number of attempts which will be made to reconnect to an unreachable primary (or other upstream node)
reconnect_attempts=6                                                          

# Interval between attempts to reconnect to an unreachable primary (or other upstream node)
reconnect_interval=10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this configuration, a total of 6 attempts will be made with 10 seconds between attempts before promoting a new primary using &lt;code&gt;promote_command&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As you can see from the &lt;a href="https://repmgr.org/docs/repmgr.html"&gt;documentation&lt;/a&gt;, &lt;code&gt;promote_command&lt;/code&gt; in Repmgr configuration is used in a failover situation to promote a new primary. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;promote_command='/usr/bin/repmgr standby promote -f /etc/repmgr.conf --log-to-file'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In fact, in the case of a failover situation, something wrong is happening so it may be a good action to perform a backup in addition to promotion. For example, this command will perform a backup using pgbackrest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;promote_command='/usr/bin/repmgr standby promote -f /etc/repmgr.conf --log-to-file &amp;amp;&amp;amp; sleep 120 &amp;amp;&amp;amp; pgbackrest --stanza=my_stanza --type=full backup'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;p&gt;PostgreSQL Replication statistics are available on current primary. An overall vision can be seen on primary node by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from pg_stat_replication;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pg_stat_replication&lt;/code&gt; contains statistics about each WAL sender process connected to a standby process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-[ RECORD 1 ]----+----------------------------------------------
pid              | 11881
usesysid         | 16388
usename          | repmgr
application_name | &amp;lt;application_name&amp;gt;
client_addr      | &amp;lt;ip&amp;gt;
client_hostname  | 
client_port      | 58212
backend_start    | 2019-11-12 16:52:04.51763+01
backend_xmin     | 
state            | streaming
sent_lsn         | 138/6C000000
write_lsn        | 138/6C000000
flush_lsn        | 138/6C000000
replay_lsn       | 138/6C000000
write_lag        | 
flush_lag        | 00:00:00.29105
replay_lag       | 
sync_priority    | 0
sync_state       | async
-[ RECORD 2 ]----+----------------------------------------------
pid              | 11879
usesysid         | 16388
usename          | repmgr
application_name | &amp;lt;application_name&amp;gt;
client_addr      | &amp;lt;ip&amp;gt;
client_hostname  | 
client_port      | 35170
backend_start    | 2019-11-12 16:52:03.053909+01
backend_xmin     | 
state            | streaming
sent_lsn         | 138/6C000000
write_lsn        | 138/6C000000
flush_lsn        | 138/6C000000
replay_lsn       | 138/6C000000
write_lag        | 
flush_lag        | 00:00:00.268068
replay_lag       | 
sync_priority    | 0
sync_state       | async
-[ RECORD 3 ]----+----------------------------------------------
pid              | 5201
usesysid         | 16388
usename          | repmgr
application_name | &amp;lt;application_name&amp;gt;
client_addr      | &amp;lt;ip&amp;gt;
client_hostname  | 
client_port      | 52130
backend_start    | 2019-11-08 16:22:01.688119+01
backend_xmin     | 
state            | streaming
sent_lsn         | 138/6C000000
write_lsn        | 138/6C000000
flush_lsn        | 138/6C000000
replay_lsn       | 138/6C000000
write_lag        | 
flush_lag        | 00:00:00.23605
replay_lag       | 
sync_priority    | 0
sync_state       | async
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First of all, &lt;code&gt;sync_state&lt;/code&gt; column indicates what type of replication used. In this example, the value &lt;code&gt;async&lt;/code&gt; only shows that is an asynchronous replication and it’s definitely not a problem as I have seen explained in some articles. When you setup a replication cluster, you had to choose between asynchronous and synchronous replication.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;postgresql.conf&lt;/code&gt; file, it’s possible to specify a list of standby servers to &lt;a href="https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION"&gt;support synchronous replication&lt;/a&gt; with &lt;code&gt;synchronous_standby_names&lt;/code&gt;. It means that transactions will commit only after standby synchronous servers confirm receipt of the data.&lt;/p&gt;

&lt;p&gt;What is important to look is &lt;code&gt;state&lt;/code&gt; column. Value &lt;code&gt;streaming&lt;/code&gt; indicates the WAL sender is streaming changes to its connected standby server. Then, an important health indicator is the amount of WAL records generated the primary node, but not yet applied by standby server: streaming lag. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sent_lsn&lt;/code&gt; shows the last WAL sent on WAL sender connection. LSN stands for Log Sequence Number and it’s a position in the Write-Ahead Log stream. Thus, an important gap between current WAL and &lt;code&gt;sent_lsn&lt;/code&gt; may indicate that primary server is under heavy load. We can get current WAL by using &lt;code&gt;pg_current_wal_lsn&lt;/code&gt; function and &lt;code&gt;pg_wal_lsn_diff&lt;/code&gt; to compute the difference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select (pg_wal_lsn_diff(pg_current_wal_lsn(),sent_lsn)) as primary_streaming_lag FROM pg_stat_replication;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The result is in bytes.&lt;/p&gt;

&lt;p&gt;The view &lt;code&gt;pg_stat_replication&lt;/code&gt; provides also the last WAL position written, flushed and replayed on standby database. This way, we can have the standby total streaming lag by executing this query for each standby node :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select (pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn)) as standby_streaming_lag FROM pg_stat_replication;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select application_name,
pg_current_wal_lsn() as current_WAL_lsn,
sent_lsn as last_sent_WAL,
replay_lsn last_replay_WAL,
(pg_wal_lsn_diff(pg_current_wal_lsn(),sent_lsn))::int / 1024 as primary_streaming_lag,
(pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn))::int / 1024 as standby_streaming_lag
FROM pg_stat_replication;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let’s check this query by adding some network latency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tc qdisc add dev eth0 root handle 1: prio priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
tc qdisc add dev eth0 parent 1:2 handle 20: netem delay 1000ms
tc filter add dev eth0 parent 1:0 protocol ip u32 match ip dst &amp;lt;ip mask&amp;gt; flowid 1:2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This command adds a delay of 1 second for nodes that match a specific IP range.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select application_name,
pg_current_wal_lsn() as current_WAL_lsn,
sent_lsn as last_sent_WAL,
replay_lsn last_replay_WAL,
(pg_wal_lsn_diff(pg_current_wal_lsn(),sent_lsn))::int / 1024 as primary_streaming_lag,
(pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn))::int / 1024 as standby_streaming_lag
FROM pg_stat_replication;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-[ RECORD 1 ]---------+----------------------------------------------
application_name      | &amp;lt;application_name&amp;gt;
current_wal_lsn       | 138/7D054AF8
last_sent_wal         | 138/7D054AF8
last_replay_wal       | 138/7D054AF8
primary_streaming_lag | 0
standby_streaming_lag | 0
-[ RECORD 2 ]---------+----------------------------------------------
application_name      | &amp;lt;application_name&amp;gt;
current_wal_lsn       | 138/7D054AF8
last_sent_wal         | 138/7D054AF8
last_replay_wal       | 138/7D000000
primary_streaming_lag | 0
standby_streaming_lag | 338
-[ RECORD 3 ]---------+----------------------------------------------
application_name      | &amp;lt;application_name&amp;gt;
current_wal_lsn       | 138/7D054AF8
last_sent_wal         | 138/7D054AF8
last_replay_wal       | 138/7D000000
primary_streaming_lag | 0
standby_streaming_lag | 338
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;primary_streaming_lag&lt;/code&gt; and  &lt;code&gt;standby_streaming_lag&lt;/code&gt; values are in KB as it’s divided by 1024. This is nice but it’s only available on primary node. If we are experiencing lag on a standby node, it can mean that this node is under heavy load or network latency. It’s important to monitor replication directly on standby nodes. And so, Repmgr has its own table to monitor replication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from repmgr.replication_status;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-[ RECORD 1 ]-------------+----------------------------------------------
primary_node_id           | 1
standby_node_id           | 3
standby_name              | &amp;lt;application_name&amp;gt;
node_type                 | standby
active                    | t
last_monitor_time         | 2019-11-22 11:07:51.673005+01
last_wal_primary_location | 143/4C009390
last_wal_standby_location | 143/4C009390
replication_lag           | 0 bytes
replication_time_lag      | 00:00:00
apply_lag                 | 0 bytes
communication_time_lag    | 00:00:00.960348
-[ RECORD 2 ]-------------+----------------------------------------------
primary_node_id           | 1
standby_node_id           | 4
standby_name              | &amp;lt;application_name&amp;gt;
node_type                 | standby
active                    | t
last_monitor_time         | 2019-11-22 11:07:51.100838+01
last_wal_primary_location | 143/4C0091D0
last_wal_standby_location | 143/4C0091D0
replication_lag           | 0 bytes
replication_time_lag      | 00:00:00
apply_lag                 | 0 bytes
communication_time_lag    | 00:00:01.532515
-[ RECORD 3 ]-------------+----------------------------------------------
primary_node_id           | 1
standby_node_id           | 2
standby_name              | &amp;lt;application_name&amp;gt;
node_type                 | standby
active                    | t
last_monitor_time         | 2019-11-22 11:07:51.310996+01
last_wal_primary_location | 143/4C0092B0
last_wal_standby_location | 143/4C0092B0
replication_lag           | 0 bytes
replication_time_lag      | 00:00:00
apply_lag                 | 0 bytes
communication_time_lag    | 00:00:01.322357
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This view is created and available on each node, primary and standby. You can check how this view is built on &lt;a href="https://github.com/2ndQuadrant/repmgr/blob/master/repmgr--4.4.sql"&gt;Repmgr Github&lt;/a&gt;, depends your Repmgr version.&lt;/p&gt;

&lt;p&gt;Furthermore, Repmgr offers a check service by node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/repmgr -f /etc/repmgr.conf node check
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node "&amp;lt;application_name&amp;gt;":
    Server role: OK (node is standby)
    Replication lag: OK (0 seconds)
    WAL archiving: OK (10 pending archive ready files)
    Downstream servers: OK (this node has no downstream nodes)
    Replication slots: OK (node has no physical replication slots)
    Missing physical replication slots: OK (node has no missing physical replication slots)
    Configured data directory: OK (configured "data_directory" is "&amp;lt;data_directory&amp;gt;")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Replication lag checks if the node is lagging by more than &lt;code&gt;replication_lag_warning&lt;/code&gt; and &lt;code&gt;replication_lag_critical&lt;/code&gt; parameters. By default, it’s 300 and 600 ms.&lt;/p&gt;




&lt;p&gt;A big thanks to &lt;a href="https://twitter.com/Karenhjex"&gt;Karen&lt;/a&gt; and &lt;a href=""&gt;Marc Barret&lt;/a&gt; for their time and proofreading.&lt;/p&gt;

&lt;p&gt;Photo by Jan Kolar / VUI Designer on Unsplash&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>repmgr</category>
      <category>repmgrd</category>
      <category>replication</category>
    </item>
    <item>
      <title>How to see and limit memory consumption of an application ?</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Wed, 24 Jul 2019 21:45:47 +0000</pubDate>
      <link>https://dev.to/vga/how-to-see-and-limit-memory-consumption-of-an-application-5bfl</link>
      <guid>https://dev.to/vga/how-to-see-and-limit-memory-consumption-of-an-application-5bfl</guid>
      <description>&lt;p&gt;For a few months, my computer experienced some freezing during several minutes and the only solution to return to work was a reboot. It’s really annoying so I decided to look at what’s going on.&lt;br&gt;
I have been working since three years on a laptop DELL E7450. It has 8GB RAM size and an Intel i5 core with 2 cores and 4 logical processors. It is quite enough to work with, isn’t it ?&lt;br&gt;
I’m using Ubuntu 18.04 coupled with &lt;a href="https://i3wm.org/" rel="noopener noreferrer"&gt;i3&lt;/a&gt; for my window manager. By the way, if you don’t know yet about i3, you have to take a look at it. &lt;br&gt;
I noticed that with only 2 open applications : Google Chrome and Slack, both used most of my memory. Google Chrome is well known to use a lot of RAM and Slack application is built upon Electron and bad news: &lt;a href="https://josephg.com/blog/electron-is-flash-for-the-desktop/" rel="noopener noreferrer"&gt;Electron is a known resource hog&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Memory Usage
&lt;/h2&gt;

&lt;p&gt;I’ve made some simple tests to check memory consumption. As you can see from this picture, only 2 open applications use nearly 100% of my memory.&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%2Fzpdxiqt3fvqhr692crfr.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%2Fzpdxiqt3fvqhr692crfr.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This picture is extracted from a screenshot of the htop program. Htop is a great alternative to top. It provides facilities to filter, sort, search and view per core. The thing that interested me here is the memory, especially memory per process. To do that, i’m using &lt;a href="https://manpages.ubuntu.com/manpages/precise/en/man8/smem.8.html" rel="noopener noreferrer"&gt;smem&lt;/a&gt;, a tool that calculates the USS, PSS and RSS per process.&lt;/p&gt;

&lt;p&gt;USS stands for Unique Set Size. This is the amount of unshared memory unique to that process. It does not include shared memory. In the other hand, PSS stands for Proportional Set Size. It adds together the unique memory (USS), along with a proportion of its shared memory divided by the number of processes sharing that memory. It gives a  representation of how much actual physical memory is being used per process - with shared memory truly represented as shared.&lt;/p&gt;

&lt;p&gt;RSS stands for Resident Set Size. This is the amount of shared memory plus unshared memory used by each process. If any process shares memory, this will over-report the amount of memory actually used, because the same shared memory will be counted more than once - appearing again in each other process that shares the same memory. This metric can be unreliable, especially when processes have a lot of forks.&lt;/p&gt;

&lt;p&gt;Here the command I used :&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

smem -n -s pss -t -k -P chrome


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

&lt;/div&gt;
&lt;p&gt;If you're not familiar with command line, you can use &lt;a href="https://explainshell.com/explain?cmd=smem+-n+-s+pss+-t+-k+-P+chrome" rel="noopener noreferrer"&gt;explainshell.com&lt;/a&gt;, a great website to dissect commands.&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%2Frmkjds1grjw8csfb77ya.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%2Frmkjds1grjw8csfb77ya.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To sum up, 57 processes match ‘chrome’ and used 4,9G of USS, 5.0G of PSS and 7,7G of RSS.&lt;/p&gt;

&lt;p&gt;Let’s focus on Slack memory consumption:&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%2Fefjb3rnxnwtwrf0pug5o.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%2Fefjb3rnxnwtwrf0pug5o.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Memory Limitation
&lt;/h2&gt;

&lt;p&gt;Let’s say I want to limit the memory allocated to the Slack application. My first thought was to use Docker. By wrapping the application in a Docker container, I can use Docker abilities to &lt;a href="https://docs.docker.com/config/containers/resource_constraints/" rel="noopener noreferrer"&gt;limit the resources of a container&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker run --memory=1G ….


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

&lt;/div&gt;
&lt;p&gt;This parameter will set the maximum amount of memory the container can use. It works, but it means I need to create a Docker image dedicated to all applications I want to limit the amount of memory.&lt;br&gt;
In fact, Docker uses a technology called &lt;code&gt;namespaces&lt;/code&gt; to isolate containers from other processes. To learn more about Docker architecture, you can take a look at &lt;a href="https://docs.docker.com/engine/docker-overview/" rel="noopener noreferrer"&gt;Docker overview page&lt;/a&gt;. One namespace is interesting in my case : Control groups also known as cgroups. This one enables the limitation of physical resources.&lt;/p&gt;

&lt;p&gt;Let’s use it:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# Create a group for memory named “slack_group”
cgcreate -g "memory:slack_group" -t victor:victor

# Specify memory limit to 1G for this group
cgset -r memory.limit_in_bytes=1G "slack_group"


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

&lt;/div&gt;
&lt;p&gt;To ensure memory limitation is correctly applied, it’s possible to look in directory &lt;code&gt;/sys/fs/cgroup/memory/mygroup/&lt;/code&gt; and precisely at file &lt;code&gt;memory.limit_in_bytes&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# Launch slack application in this group
cgexec -g "memory:slack_group" slack

# If needed, we can remove the group
cgdelete "memory:slack_group"


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

&lt;/div&gt;
&lt;p&gt;In my case, I use cgroups only to limit memory allocated but it’s also possible to limit CPU.&lt;/p&gt;

&lt;p&gt;Then, let’s see if it’s works. &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%2F0cxekpb8kauvcwcw25xy.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%2F0cxekpb8kauvcwcw25xy.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, PSS is strictly equal to 1G but the swap has now increased to 500M. The application is a bit slow, changing from one workspace to another is a bit long but it’s still comfortable to use.&lt;br&gt;
Let’s disable swap to see if it works.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

echo 0 &amp;gt; /sys/fs/cgroup/memory/slack_group/memory.swappiness


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

&lt;/div&gt;
&lt;p&gt;Guess what ? It doesn’t work, the application is not responding and some processes are killed. In fact, it’s the OOM Killer (Out-of-memory Killer) who is in charge to kill processes in order to free up memory for the system. The OOM Killer selects the best candidate for elimination from a score maintained by the kernel. You can see this score in:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

/proc/${PID}/oom_score


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Automation
&lt;/h2&gt;

&lt;p&gt;I know how to limit memory consumption for one application but it’s definitely not sustainable in the future. I will have to create a group per each application I want to limit memory usage. Thanks to this &lt;a href="https://unix.stackexchange.com/a/279175/363256" rel="noopener noreferrer"&gt;StackExchange question&lt;/a&gt;, I found a script that does the job. It’s available here:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This script creates a group each time it’s launched and remove it when it’s killed. &lt;br&gt;
Easy to use:&lt;/p&gt;

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

limitmem.sh 1G slack


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

&lt;/div&gt;

&lt;p&gt;That’s fine but this script is a piece of code that I will have to maintain, update, upgrade, etc….&lt;/p&gt;

&lt;p&gt;Another way to integrate memory limit to my system is to use systemd.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;systemd is a Linux initialization system and service manager that includes features like on-demand starting of daemons, mount and automount point maintenance, snapshot support, and processes tracking using Linux control groups. systemd provides a logging daemon and other tools and utilities to help with common system administration tasks. &lt;a href="https://www.linode.com/docs/quick-answers/linux-essentials/what-is-systemd/" rel="noopener noreferrer"&gt;Reference&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To do this, I have to wrap my application into a systemd service.&lt;/p&gt;

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

[Unit]
Description=slack
After=network.target 

[Service]
User=victor
Group=victor
Environment=DISPLAY=:0
ExecStart=/usr/bin/slack
#Restart=on-failure
KillMode=process
MemoryAccounting=true
MemoryMax=1G

[Install]
WantedBy=multi-user.target 


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

&lt;/div&gt;

&lt;p&gt;By specifing paramaters &lt;code&gt;MemoryAccounting&lt;/code&gt; and &lt;code&gt;MemoryMax&lt;/code&gt;, I’m able to limit memory allocated. As explained in systemd documentation, systemd organizes processes with cgroups. In my opinion, using systemd is far more sustainable than maintaining a custom shell script as it’s became the standard for most Linux distributions.&lt;/p&gt;

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

&lt;p&gt;As I was writing this article, slack engineering published an &lt;a href="https://slack.engineering/rebuilding-slack-on-the-desktop-308d6fe94ae4" rel="noopener noreferrer"&gt;article&lt;/a&gt; announcing a new Slack desktop application and I quote: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of our primary metrics has been memory usage&lt;/p&gt;
&lt;/blockquote&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%2Fvonsmk2kfge6nse6ex5s.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%2Fvonsmk2kfge6nse6ex5s.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be clear, my goal was not to prove how bad memory management is of Slack application. I simply wanted to go deeper in memory management for the operating system I use. I used slack application here like I could have used any other.&lt;/p&gt;

&lt;p&gt;By the way, all of this makes me think: do I have to let a messaging application consumes 30% of my memory? More generally, do I have to let any application manages it own memory consumption? Could the concept of container (an application in an isolated environment) be applied to my everyday applications?&lt;/p&gt;

&lt;p&gt;Don’t hesitate to tell me if I forgot a way to limit memory consumption and let me know what you think about it.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://twitter.com/saby_nastasia" rel="noopener noreferrer"&gt;Nastasia&lt;/a&gt; and &lt;a href="https://twitter.com/_mcorbin" rel="noopener noreferrer"&gt;Mathieu&lt;/a&gt; for their time and proofreading.&lt;/p&gt;

&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@hbtography" rel="noopener noreferrer"&gt;Harrison Broadbent on Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>memory</category>
      <category>linux</category>
      <category>cgroup</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Dockerize your integration tests </title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Fri, 04 Jan 2019 09:01:38 +0000</pubDate>
      <link>https://dev.to/vga/dockerize-your-integration-tests--4edm</link>
      <guid>https://dev.to/vga/dockerize-your-integration-tests--4edm</guid>
      <description>&lt;p&gt;Most of our applications have to talk to a database, a HTTP API, a message broker, a SMTP server, etc… And it's quite complicated to set up a real test environment with those components.&lt;/p&gt;

&lt;p&gt;In some cases, we can simply mock those components or have an in-memory one during test execution. For example, &lt;a href="http://www.h2database.com/html/main.html"&gt;H2&lt;/a&gt; ou &lt;a href="http://hsqldb.org/"&gt;HSQLDB&lt;/a&gt; are in-memory databases well-known for being used during integration tests. However, they are not the one used in production environment and our tests can seem unrepresentative.&lt;br&gt;
Today, it's possible to use all the power of Docker and set up a connected test environment easily thanks to &lt;a href="https://www.testcontainers.org/"&gt;Testcontainers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PIaUbmnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rnorth.org/public/testcontainers/logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PIaUbmnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rnorth.org/public/testcontainers/logo.png" alt="testcontainers logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Testcontainers
&lt;/h2&gt;

&lt;p&gt;Testcontainers allows us to easily manipulate Docker containers during test execution. It uses the Docker client &lt;a href="https://github.com/docker-java/docker-java"&gt;docker-java&lt;/a&gt; to communicate with Docker daemon. It works with most operating systems and environments and despite the best-efforts support for Windows, I use it on a daily basis with Docker Toolbox. You can find the matrix compatibility &lt;a href="https://www.testcontainers.org/compatibility.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you create a container, Testcontainers will try to connect to the Docker daemon by using &lt;code&gt;DOCKER_HOST&lt;/code&gt;, &lt;code&gt;DOCKER_TLS_VERIFY&lt;/code&gt; and &lt;code&gt;DOCKER_CERT_PATH&lt;/code&gt; variables. These environment variables can be easily overridden in the JVM for example.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a container
&lt;/h3&gt;

&lt;p&gt;Containers are represented with the object &lt;em&gt;GenericContainer&lt;/em&gt;. It's possible to create a container from an image, a Dockerfile or from a Dockerfile created on the fly. In addition, it's possible to create containers from a &lt;a href="https://www.testcontainers.org/usage/docker_compose.html"&gt;Docker Compose file&lt;/a&gt;.&lt;br&gt;
For instance, this is an Elasticsearch server created from the image &lt;a href="https://hub.docker.com/_/elasticsearch/"&gt;docker.elastic.co/elasticsearch/elasticsearch:6.1.1&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;GenericContainer&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GenericContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docker.elastic.co/elasticsearch/elasticsearch:6.1.1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withEnv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"discovery.type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"single-node"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withExposedPorts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9200&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;waitingFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="nc"&gt;Wait&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forHttp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/_cat/health?v&amp;amp;pretty"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forStatusCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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 can see that it's fairly easy to provide environment variables to the container with the method &lt;code&gt;withEnv&lt;/code&gt;. In this case, it's the variable &lt;em&gt;discovery.type&lt;/em&gt; with value &lt;em&gt;single-node&lt;/em&gt;.&lt;br&gt;
Next, we make sure that our container is up by making an HTTP call on &lt;code&gt;/_cat/health&lt;/code&gt; API and having a 200 code response. There are also other strategies to assert a container is running:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wait.forLogMessage waits for a log message,&lt;/li&gt;
&lt;li&gt;Wait.forListeningPort waits for a listening port&lt;/li&gt;
&lt;li&gt;Wait.forHealthcheck enables to use &lt;a href="https://docs.docker.com/engine/reference/builder/#healthcheck"&gt;HEALTHCHECK&lt;/a&gt; feature from docker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To finalize the container configuration, our container is exposing internal port 9200 and this is explicitly set with the method &lt;code&gt;withExposedPorts&lt;/code&gt;. It means that Testcontainers will map this container's port to a random port. It's possible to retrieve mapped port with the method &lt;code&gt;getMappedPort&lt;/code&gt;otherwise we can define port bindings with the method &lt;code&gt;setPortBindings&lt;/code&gt;. Here, we expose the port 9200 from our container to port 9200:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPortBindings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"9200:9200"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That's it! Our Elasticsearch server is ready to be used. To start it up, we simply have to execute the start method:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;At startup, Testcontainers will run a bunch of checks like the docker version or the connection to the registered Docker Registry. This can be blocking if you are working behind a company proxy, so it's possible to disable those checks by creating the file &lt;em&gt;testcontainers.properties&lt;/em&gt; in the tests resources directory with this content:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;At last, we can stop our container with the method stop.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will stop the container and also remove the attached volume. This is great because it prevents having dangling volumes.&lt;/p&gt;
&lt;h2&gt;
  
  
  During Tests
&lt;/h2&gt;

&lt;p&gt;One great strength of Testcontainers is its integration with JUnit framework. In fact, GenericContainer objects are &lt;a href="https://github.com/junit-team/junit4/wiki/rules"&gt;JUnit rules&lt;/a&gt;. It means that their lifecycle is directly bound to the test lifecycle. Thereby, by using the &lt;code&gt;@Rule&lt;/code&gt; or &lt;code&gt;@ClassRule&lt;/code&gt; JUnit annotations, our containers will be initialized before the test start-up and stopped at the end of the tests execution.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ClassRule&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;GenericContainer&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GenericContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"redis:3.0.2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withExposedPorts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Nevertheless, it means that Testcontainers will come with a JUnit 4 dependency and it can be annoying if your tests run with &lt;a href="https://junit.org/junit5/docs/current/user-guide/#overview-what-is-junit-5"&gt;JUnit 5&lt;/a&gt;. Indeed, JUnit has replaced the Rule concept with &lt;a href="https://junit.org/junit5/docs/current/user-guide/#extensions"&gt;Extension&lt;/a&gt;. Since the version 1.10.0 released on November 2018, Testcontainers &lt;a href="https://www.testcontainers.org/usage.html#junit"&gt;supports now JUnit 5&lt;/a&gt; and it's possible to use extensions with the help of &lt;code&gt;@Testcontainers&lt;/code&gt;and &lt;code&gt;@Container&lt;/code&gt; annotations from the dedicated library junit-jupiter:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&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;testcontainers&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;junit-jupiter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.10.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Preconfigured container
&lt;/h2&gt;

&lt;p&gt;Like Docker, Testcontainers ecosystem is very rich. You can find preconfigured containers like MySql, PostgreSQL, Oracle database, Kafka, Neo4j, Elasticsearch, etc.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Rule&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;KafkaContainer&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KafkaContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can browse the list directly from &lt;a href="https://search.maven.org/search?q=g:org.testcontainers"&gt;maven repository&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  A concrete case
&lt;/h1&gt;

&lt;p&gt;Let's see a concrete example of using Testscontainers with the &lt;a href="https://github.com/spring-projects/spring-petclinic"&gt;Spring PetClinic application&lt;/a&gt;. It's a demonstrating project based on several Spring components like Spring Boot, Spring MVC and Spring JPA. This application aims at managing a pet clinic with pets, pet owners and vets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F-e4U47x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6dmhjw1jun0azij8d3zk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F-e4U47x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6dmhjw1jun0azij8d3zk.png" alt="application petclinic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The controller layer exposes HTTP endpoints to create and read entities. Then, the persistence layer communicates with a relational database. The application can be configured to communicate with a HSQLDB or a MySql database.&lt;/p&gt;

&lt;p&gt;The persistence layer is tested with integration tests and those uses an in-memory HSQL database while the persistence layer itself uses a MySql database.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;First, we have to install Docker on the machine which is going to execute tests. Then, we need to add the Testcontainers dependency to the project. In this case, we simply add the following to the &lt;em&gt;pom.xml&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&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;org.testcontainers&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;testcontainers&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.10.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Database configuration
&lt;/h2&gt;

&lt;p&gt;The default database configuration is done in the &lt;em&gt;application.properties&lt;/em&gt; file.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;database=hsqldb
spring.datasource.schema=classpath*:db/${database}/schema.sql
spring.datasource.data=classpath*:db/${database}/data.sql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As we can see, this is an in-memory HSQLDB database initialized with a schema from the &lt;em&gt;schema.sql&lt;/em&gt; file. Then, the database is populated with the &lt;em&gt;data.sql&lt;/em&gt; file. This is the default project configuration.&lt;br&gt;
We need to create &lt;em&gt;application-test.properties&lt;/em&gt; file to configure a connection to a MySql database.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.datasource.url=jdbc:mysql://localhost/petclinic
spring.datasource.username=petclinic
spring.datasource.password=petclinic
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Next, let's take the test class &lt;code&gt;ClinicServiceTests.java&lt;/code&gt;. This class contains all integration tests for the persistence layer. First of all, we need to change Spring test configuration to ensure that the tests will use our database connection.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@TestPropertySource&lt;/code&gt; annotation enables to load our file &lt;em&gt;application-test.properties&lt;/em&gt; and &lt;code&gt;@AutoConfigureTestDatabase&lt;/code&gt; with the &lt;code&gt;NONE&lt;/code&gt; value prevents Spring from creating an embedded database.&lt;/p&gt;

&lt;h2&gt;
  
  
  MySql container
&lt;/h2&gt;

&lt;p&gt;Let's create a MySql database that matches requirements from our tests. In this instance, we use the ability from Testcontainers to create a Docker image from a Dockerfile created on the fly. As a first step, we have pulled a &lt;a href="https://hub.docker.com/_/mysql/"&gt;MySql official image&lt;/a&gt; from Docker Hub:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, we have to create our database and the connection's user. This is done by using environment variables from the Docker image.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next, we have to create a database schema and populate the database. From the image documentation, the directory &lt;em&gt;/docker-entrypoint-initdb.d&lt;/em&gt; is scanned at startup and all files with &lt;em&gt;.sh&lt;/em&gt;, &lt;em&gt;.sql&lt;/em&gt; et &lt;em&gt;.sql.gz&lt;/em&gt; extension are executed. So, we just have to put our files &lt;em&gt;schema.sql&lt;/em&gt; and &lt;em&gt;data.sql&lt;/em&gt; in this directory.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;By using &lt;code&gt;withClasspathResourceMapping&lt;/code&gt;, the files &lt;em&gt;schema.sql&lt;/em&gt; and &lt;em&gt;data.sql&lt;/em&gt; are put on the classpath into the container as a volume. Then, we can access it into our Dockerfile construction.&lt;br&gt;
One last thing, we have to expose the default MySql port: 3306.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Unfortunately, we can't directly set port bindings with the method &lt;em&gt;setPortBindings&lt;/em&gt;. We have to customize the container on creation with the method &lt;code&gt;withCreateContainerCmdModifier&lt;/code&gt;. Finally, we are waiting for the listening port to ensure that our container is up.&lt;br&gt;
Voilà! With few lines of code, we have easily set a MySql database for our tests without having to manage the container lifecycle. The &lt;code&gt;@ClassRule&lt;/code&gt; annotation makes our container starting once for all the tests. You might be wondering: have we extend the test execution time? In fact, it only takes 907 ms with a Docker container against 860 ms with a HSQLDB in-memory database. The source code shown in this section is available on &lt;a href="https://github.com/vgallet/spring-petclinic/tree/testcontainers"&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A big thanks to &lt;a href="https://www.linkedin.com/in/sonyth-huber-57854424/"&gt;Sonyth&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/s%C3%A9bastien-bernard-841598176/"&gt;Sebastien&lt;/a&gt;, &lt;a href="https://twitter.com/Ouelcum"&gt;Laurent&lt;/a&gt;, &lt;a href="https://twitter.com/_louidji"&gt;Louis&lt;/a&gt; and &lt;a href="https://twitter.com/ncuillery"&gt;Nicolas&lt;/a&gt; for their time and proofreading.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>docker</category>
      <category>testcontainers</category>
      <category>tests</category>
    </item>
    <item>
      <title>Builder Pattern, a first step to DSL</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Wed, 05 Dec 2018 19:13:09 +0000</pubDate>
      <link>https://dev.to/vga/builder-pattern-a-first-step-to-dsl-47de</link>
      <guid>https://dev.to/vga/builder-pattern-a-first-step-to-dsl-47de</guid>
      <description>

&lt;p&gt;When you are looking for an explanation of Builder pattern, you will probably find some articles all showing a class dedicated to creating an object. It's quite simple and we can go deeper with this pattern. &lt;/p&gt;

&lt;p&gt;Let's start from the beginning with the class &lt;code&gt;Person&lt;/code&gt; below: &lt;/p&gt;



&lt;div class="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;Person&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

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

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

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

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

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

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

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

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;city&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;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;firstname&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;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lastname&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;nickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gender&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;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;country&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;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;city&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;As we can see from this piece of code, there will be problems when creating a new Person object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;constructor that's too big,&lt;/li&gt;
&lt;li&gt;constructor parameters have all the same type. We have to remember the right order of each parameter when using it. In fact, we are façing a common code smell: &lt;strong&gt;primitive obsession&lt;/strong&gt;. You can take a look at this &lt;a href="https://refactoring.guru/smells/primitive-obsession"&gt;article&lt;/a&gt; which explains how to recognize and deal with them.&lt;/li&gt;
&lt;li&gt;How can we set up constraints? It can be difficult to check nullity or to ensure consistency between fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So to deal with some of these points, we can add several constructors. For example:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&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="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nickname&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="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&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;By adding different constructors to our class Person, the result is that &lt;strong&gt;building responsibility is delegated to the client&lt;/strong&gt;. The developer who wants to create an object Person has to know which constructor to use and why. Moreover, the resulting code is difficult to read and to understand :&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"smith"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this simple piece of code, it's difficult to know where the first name, last name, and nickname parameters are. We have to go through the source code to check on which fields will be initialized. An handy solution is to create a builder class to address this readability problem.&lt;/p&gt;



&lt;div class="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;PersonBuilder&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="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;PersonBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;PersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;PersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"firstname must be not null"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;PersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lastname must be not null"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;person&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;Then, we can use it like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PersonBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smith"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Great! This solution has the benefit of explicit arguments. We can easily understand what person's first name is. In addition, it was easy to add a not-null constraint for each building method. Furthermore, as each method returns the instance of PersonBuilder, it provides us a pseudo &lt;a href="https://en.wikipedia.org/wiki/Fluent_interface"&gt;DomainSpecificLanguage&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, unlike a constructor, this builder is not self-explanatory and can be used incorrectly. For example:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PersonBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This simplest case reveals a lack of guidance. In fact, it's possible to guide the developer during the creation phase. &lt;br&gt;
For example, let's say we want to divide the creation process into four steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the developer has to set the first name first,&lt;/li&gt;
&lt;li&gt;then he can set the last name,&lt;/li&gt;
&lt;li&gt;then he can set the email&lt;/li&gt;
&lt;li&gt;and finally he can build a Person object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this, we have to create four interfaces :&lt;/p&gt;



&lt;div class="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;StepFirstnameBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="n"&gt;StepLastnamePersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&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 first step enables the developer to set the first name field and then to use the second step interface &lt;code&gt;StepLastnamePersonBuilder&lt;/code&gt;.&lt;/p&gt;



&lt;div class="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;StepLastnamePersonBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="n"&gt;StepEmailPersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&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;div class="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;StepEmailPersonBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="n"&gt;FinalStepPersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FinalStepPersonBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;build&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;Finally, after setting all mandatory fields we can access the &lt;code&gt;build&lt;/code&gt; method.&lt;br&gt;
That's it! Now we can modify &lt;code&gt;PersonBuilder&lt;/code&gt; class to implement our four steps.&lt;/p&gt;



&lt;div class="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;PersonBuilder&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;StepFirstnameBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
&lt;span class="n"&gt;StepLastnamePersonBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;StepEmailPersonBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;FinalStepPersonBuilder&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="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;PersonBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;StepFirstnameBuilder&lt;/span&gt; &lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonBuilder&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="n"&gt;StepLastnamePersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"firstname must be not null"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="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="n"&gt;StepEmailPersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lastname must be not null"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="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="n"&gt;FinalStepPersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;withEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="n"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;person&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;Now, let's use it:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PersonBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; returrns an instance of StepFirstnameBuilder&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withFirstname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; returns an instance of StepLastnamePersonBuilder&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withLastname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smith"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; returns an instance of StepEmailPersonBuilder&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"john@smith.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; returns an instance of FinalStepPersonBuilder&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By implementing all these steps, we have totally controlled the way a Person object is built. Actually, we have just created a DomainSpecificLanguage. This Builder pattern is a particular case of FluentInterface dedicated to building object and it's an easy way to express the way an object is built.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A big thanks to &lt;a href="https://www.linkedin.com/in/sonyth-huber-57854424/"&gt;Sonyth&lt;/a&gt; and &lt;a href="https://twitter.com/TsubaR00ck"&gt;Mickael&lt;/a&gt; for their time and proofreading.&lt;/em&gt;&lt;/p&gt;


</description>
      <category>java</category>
      <category>designpattern</category>
      <category>builder</category>
    </item>
    <item>
      <title>Migration from Junit 4 to Junit 5</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Mon, 23 Apr 2018 07:25:29 +0000</pubDate>
      <link>https://dev.to/vga/migration-from-junit-4-to-junit-5-19d6</link>
      <guid>https://dev.to/vga/migration-from-junit-4-to-junit-5-19d6</guid>
      <description>&lt;p&gt;While working on my current project, I got some time to migrate from &lt;a href="https://junit.org/junit4/" rel="noopener noreferrer"&gt;JUnit 4&lt;/a&gt; to &lt;a href="https://junit.org/junit5/" rel="noopener noreferrer"&gt;JUnit 5&lt;/a&gt;.&lt;br&gt;
Since JUnit 5 was released in September 2017, it's the right time to take a look at it.&lt;/p&gt;

&lt;p&gt;My application is a java 8 maven project divided into 7 maven modules and each module has it owns integration and unit tests. However, one of these modules is dedicated to tests. It contains all the test needed dependencies and it's injected as scope test into others modules.&lt;br&gt;
Our tests dependencies are the most common in a Java project. We use JUnit 4, &lt;a href="https://joel-costigliola.github.io/assertj/" rel="noopener noreferrer"&gt;AssertJ&lt;/a&gt;, &lt;a href="http://site.mockito.org/" rel="noopener noreferrer"&gt;Mockito&lt;/a&gt;, &lt;a href="http://dbunit.sourceforge.net/" rel="noopener noreferrer"&gt;DbUnit&lt;/a&gt; and &lt;a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html" rel="noopener noreferrer"&gt;Spring Test&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;At last, we also have a dedicated project to run end-to-end testings based on &lt;a href="https://www.seleniumhq.org/" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt;, &lt;a href="http://fluentLenium.org/" rel="noopener noreferrer"&gt;Fluentlenium&lt;/a&gt; and &lt;a href="http://jgiven.org/" rel="noopener noreferrer"&gt;JGiven&lt;/a&gt;.&lt;br&gt;
Unfortunately, JGiven does not fully support JUnit 5. It's currently in an &lt;a href="http://jgiven.org/userguide/#_junit_5_experimental" rel="noopener noreferrer"&gt;experimental state&lt;/a&gt;, so I haven't started this migration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;Let's start by adding the new JUnit dependencies :&lt;br&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;dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.jupiter&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;junit-jupiter-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit.version}&lt;span class="nt"&gt;&amp;lt;/version&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;org.junit.vintage&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;junit-vintage-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit.version}&lt;span class="nt"&gt;&amp;lt;/version&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;org.junit.platform&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;junit-platform-launcher&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit.platform.version}&lt;span class="nt"&gt;&amp;lt;/version&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;org.junit.platform&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;junit-platform-runner&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit.platform.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;The important to take note of is the import of &lt;code&gt;junit-vintage-engine&lt;/code&gt;. It provides the ability to run JUnit 4 tests and JUnit 5 tests simultaneously without difficulty.&lt;/p&gt;
&lt;h2&gt;
  
  
  Unit Tests
&lt;/h2&gt;

&lt;p&gt;The next step is to replace all imports of old JUnit annotations by the newest.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.Test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;become&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here's the mapping of each annotation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;JUnit 4&lt;/th&gt;
&lt;th&gt;Junit 5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;org.junit.Before&lt;/td&gt;
&lt;td&gt;org.junit.jupiter.api.BeforeEach&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org.junit.After&lt;/td&gt;
&lt;td&gt;org.junit.jupiter.api.After&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org.junit.BeforeClass&lt;/td&gt;
&lt;td&gt;org.junit.jupiter.api.BeforeAll&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org.junit.AfterClass&lt;/td&gt;
&lt;td&gt;org.junit.jupiter.api.AfterAll&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org.junit.Ignore&lt;/td&gt;
&lt;td&gt;org.junit.jupiter.api.Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As we use AssertJ for all our assertions, I didn't need to migrate JUnit 4 assertions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;p&gt;One the biggest change is the removal of the concept of &lt;a href="http://www.codeaffine.com/2012/09/24/junit-rules/" rel="noopener noreferrer"&gt;rules&lt;/a&gt;, that has been replaced by &lt;a href="https://junit.org/junit5/docs/current/user-guide/#extensions" rel="noopener noreferrer"&gt;extension model&lt;/a&gt;. The purpose of extension is to extend the behavior of test classes or methods and it replaces JUnit runner and Junit Rules.&lt;/p&gt;

&lt;p&gt;One rule that we all have used is &lt;code&gt;ExpectedException&lt;/code&gt; and it can be easily replaced by JUnit &lt;code&gt;assertThrows&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;   &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;exceptionTesting&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a message"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a message"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Another well-known rule to migrate is &lt;code&gt;TemporaryFolder&lt;/code&gt;. Unfortunately, JUnit 5 does not provide a replacement yet. There is an open &lt;a href="http://github.com/junit-team/junit5/issues/1247" rel="noopener noreferrer"&gt;issue&lt;/a&gt; in Github. &lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/junit-team/junit5/issues/1247" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Introduce a TemporaryFolder extension
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1247&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/sbrannen" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars0.githubusercontent.com%2Fu%2F104798%3Fv%3D4" alt="sbrannen avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/sbrannen" rel="noopener noreferrer"&gt;sbrannen&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/junit-team/junit5/issues/1247" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 18, 2018&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Overview&lt;/h2&gt;
&lt;p&gt;See discussion at &lt;a href="https://github.com/junit-team/junit5-samples/issues/4" rel="noopener noreferrer"&gt;https://github.com/junit-team/junit5-samples/issues/4&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Related Issues&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;#219&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Deliverables&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[X] &lt;del&gt;Introduce an official &lt;code&gt;TemporaryFolder&lt;/code&gt; extension for JUnit Jupiter analogous to the rule support in JUnit 4.&lt;/del&gt;
&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/junit-team/junit5/issues/1247" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;So what can we do to make it work?&lt;/p&gt;

&lt;p&gt;First of all, it's possible to keep tests using those rule in JUnit 4 thanks to &lt;code&gt;junit-vintage-engine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another solution is to continue to use JUnit 4 &lt;code&gt;TemporaryFolder&lt;/code&gt; rule by adding the dependency &lt;code&gt;junit-jupiter-migrationsupport&lt;/code&gt;.&lt;br&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;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.jupiter&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;junit-jupiter-migrationsupport&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This module enables to run JUnit 5 tests with rules. For example :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@EnableRuleMigrationSupport&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;JUnit4TemporaryFolderTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Rule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;TemporaryFolder&lt;/span&gt; &lt;span class="n"&gt;temporaryFolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TemporaryFolder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&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;test&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;temporaryFolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"new_file"&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;However, this feature only supports :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rules that extend &lt;code&gt;org.junit.rules.ExternalResource&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;rules that extend &lt;code&gt;org.junit.rules.Verifier&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;rule &lt;code&gt;ExpectedException&lt;/code&gt;
and it's currently marked as &lt;a href="https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4-rule-support" rel="noopener noreferrer"&gt;experimental&lt;/a&gt; so use it at your own risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, one solution is to create our own &lt;a href="https://gist.github.com/vgallet/8b52247c4cc57c6bc96923daff630fc1" rel="noopener noreferrer"&gt;&lt;code&gt;TemporaryFolderExtension&lt;/code&gt;&lt;/a&gt; based on Junit 4 implementation.&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;TemporaryFolderExtension&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;BeforeEachCallback&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AfterEachCallback&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;File&lt;/span&gt; &lt;span class="n"&gt;parentFolder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TemporaryFolderExtension&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="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

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

   &lt;span class="nd"&gt;@Override&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExtensionContext&lt;/span&gt; &lt;span class="n"&gt;extensionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;recursiveDelete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;folder&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;@Override&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExtensionContext&lt;/span&gt; &lt;span class="n"&gt;extensionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTempFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"junit"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parentFolder&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mkdir&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="nf"&gt;newFile&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;fileName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getRoot&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createNewFile&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a file with the name \'"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\' already exists in the test folder"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="nf"&gt;newFolder&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;folderName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getRoot&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;folderName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mkdir&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;file&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;recursiveDelete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listFiles&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;recursiveDelete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;each&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="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="nf"&gt;getRoot&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"the temporary folder has not yet been created"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This implementation does not fully support all extension features like &lt;a href="https://junit.org/junit5/docs/current/user-guide/#extensions-parameter-resolution" rel="noopener noreferrer"&gt;Parameter Resolution&lt;/a&gt; but at least, it allows us to fully migrate our tests to JUnit 5.&lt;br&gt;
In addition, it's possible to inject extensions as rule by using &lt;a href="https://junit.org/junit5/docs/current/user-guide/#extensions-registration-programmatic" rel="noopener noreferrer"&gt;&lt;code&gt;@RegisterExtension&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RegisterExtension&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;TemporaryFolderExtension&lt;/span&gt; &lt;span class="n"&gt;temporaryFolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TemporaryFolderExtension&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This annotation enables us to build an extension with parameters and to access is during test execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Rules
&lt;/h2&gt;

&lt;p&gt;In my case, I had only one custom rule to migrate. Its goal is to create an in-memory SMTP server for asserting sending emails.&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;SMTPServerRule&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ExternalResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;GreenMail&lt;/span&gt; &lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SMTPServerRule&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="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SMTPServerRule&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&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="s"&gt;"localhost"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SMTPServerRule&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;hostname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&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;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hostname&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&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;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;before&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

       &lt;span class="n"&gt;smtpServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GreenMail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ServerSetup&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"smtp"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
       &lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ExpectedMail&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getMessages&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Lists&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newArrayList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReceivedMessages&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mimeMessage&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ExpectedMail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transformMimeMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mimeMessage&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&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;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&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;To make it work as a JUnit extension, it only needs to implement &lt;code&gt;BeforeEachCallback&lt;/code&gt; and &lt;code&gt;AfterEachCallback&lt;/code&gt; interfaces instead of inheriting from &lt;code&gt;ExternalResource&lt;/code&gt;. The main implementation is still the same.&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;SMTPServerExtension&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;BeforeEachCallback&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AfterEachCallback&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;GreenMail&lt;/span&gt; &lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SMTPServerExtension&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="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SMTPServerExtension&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&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="s"&gt;"localhost"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SMTPServerExtension&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;hostname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&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;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hostname&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ExpectedMail&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getMessages&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Lists&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newArrayList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReceivedMessages&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mimeMessage&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ExpectedMail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transformMimeMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mimeMessage&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;


   &lt;span class="nd"&gt;@Override&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExtensionContext&lt;/span&gt; &lt;span class="n"&gt;extensionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="nd"&gt;@Override&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExtensionContext&lt;/span&gt; &lt;span class="n"&gt;extensionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;smtpServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GreenMail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ServerSetup&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"smtp"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
       &lt;span class="n"&gt;smtpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Integration Tests
&lt;/h2&gt;

&lt;p&gt;Next, I had to update Spring integration tests and it was quite easy as class &lt;code&gt;SpringExtension&lt;/code&gt; is included in Spring 5.&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;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SpringJUnit4ClassRunner&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;become&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;@ExtendWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SpringExtension&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mockito Tests
&lt;/h2&gt;

&lt;p&gt;Let's continue with tests that use Mockito. Like we have done with Spring integration tests, we have to register an extension :&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;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockitoJUnitRunner&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;become&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;@ExtendWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockitoExtension&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, class &lt;code&gt;MockitoExtension&lt;/code&gt; is not provided by Mockito yet and it will be introduced with Mockito 3.&lt;br&gt;
One solution is the same as &lt;code&gt;TemporaryFolderExtension&lt;/code&gt;...that is to keep our tests in JUnit 4. However, it's also possible to create our own extension and so Junit team give one implementation of &lt;a href="https://github.com/junit-team/junit5-samples/blob/r5.1.1/junit5-mockito-extension/src/main/java/com/example/mockito/MockitoExtension.java" rel="noopener noreferrer"&gt;&lt;code&gt;MockitoExtension&lt;/code&gt;&lt;/a&gt; in its samples.&lt;br&gt;
I decided to import it into my project to complete my migration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Remove JUnit 4
&lt;/h2&gt;

&lt;p&gt;Then, to ensure all my tests run under JUnit 5, I checked if there is any JUnit 4 dependency by executing :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn dependency:tree

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

&lt;/div&gt;



&lt;p&gt;And so, I had to exclude some of them :&lt;br&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;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&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;spring-boot-starter-test&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;junit&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;junit&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/exclusions&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;org.dbunit&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;dbunit&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${dbunit.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;junit&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;junit&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/exclusions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Maven
&lt;/h2&gt;

&lt;p&gt;Last but not least, I needed to update the maven surefire plugin to make it works with JUnit 5.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--
        The Surefire Plugin is used during the test phase of the build lifecycle to execute the unit tests of an application.
        --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&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;maven-surefire-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${maven-surefire-plugin.version}&lt;span class="nt"&gt;&amp;lt;/version&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;org.junit.platform&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;junit-platform-surefire-provider&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1.1&lt;span class="nt"&gt;&amp;lt;/version&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;org.junit.jupiter&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;junit-jupiter-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit.version}&lt;span class="nt"&gt;&amp;lt;/version&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;/plugin&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Be careful with the version of your maven surefire plugin as the &lt;code&gt;2.20&lt;/code&gt; has a &lt;a href="https://github.com/junit-team/junit5/issues/809" rel="noopener noreferrer"&gt;memory leak&lt;/a&gt;. &lt;a href="https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven" rel="noopener noreferrer"&gt;JUnit documentation&lt;/a&gt; suggests the version &lt;code&gt;2.21&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;This migration was really easy, but even so, JUnit 5 is totally different from JUnit 4. In the end, I was able to remove the import of &lt;code&gt;junit-vintage-engine&lt;/code&gt; as I don't have Junit 4 test anymore. I only regret the fact that I had to create my own temporary folder extension and Mockito extension.&lt;br&gt;
Finally, it's possible to get more help with your migration by consulting &lt;a href="https://github.com/junit-team/junit5-samples" rel="noopener noreferrer"&gt;Junit5-samples&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A big thanks to &lt;a href="https://www.linkedin.com/in/sonyth-huber-57854424/" rel="noopener noreferrer"&gt;Sonyth&lt;/a&gt;, &lt;a href="https://twitter.com/TsubaR00ck" rel="noopener noreferrer"&gt;Mickael&lt;/a&gt; and &lt;a href="https://twitter.com/7ouss3m" rel="noopener noreferrer"&gt;Houssem&lt;/a&gt; for their time and proofreading.&lt;/p&gt;

</description>
      <category>java</category>
      <category>junit</category>
      <category>junit5</category>
      <category>junit4</category>
    </item>
    <item>
      <title>CNC2018 5 Blog ideas</title>
      <dc:creator>Victor Gallet</dc:creator>
      <pubDate>Tue, 30 Jan 2018 14:45:05 +0000</pubDate>
      <link>https://dev.to/vga/cnc2018-5-blog-ideas-1eio</link>
      <guid>https://dev.to/vga/cnc2018-5-blog-ideas-1eio</guid>
      <description>&lt;h1&gt;
  
  
  CNC2018 Blog More - Mission 1
&lt;/h1&gt;

&lt;p&gt;Hey guys, I'm currently involved in #BlogMore challenge from &lt;a href="https://2018.codenewbie.org/"&gt;CNC2018&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My first mission is to look for ideas and to validate them. Here are my five ideas, let me know what's on your mind :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How I created custom JUnit annotations for Elasticsearch integration tests. It's a simple example of how you can create custom annotations to set up test fixtures in Java.&lt;/li&gt;
&lt;li&gt;What’s new in the next release of Chrome DevTools.&lt;/li&gt;
&lt;li&gt;A summary of my first time at &lt;a href="http://snowcamp.io/en/"&gt;Snowcamp&lt;/a&gt;, a French technical conference.&lt;/li&gt;
&lt;li&gt;A feedback on how we do high availability and continuous delivery in my current project. It will be about all technologies involved in the process of development, validation, delivery of a web application and also interactions between people.&lt;/li&gt;
&lt;li&gt;How to set up a simple Elasticsearch search and autocompletion mechanism into your legacy application. It's will be in Java.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank for your feedback and don't hesitate to ask me precision.&lt;/p&gt;

</description>
      <category>blogmore</category>
      <category>cnc2018</category>
      <category>codenewbie</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
