<?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: Mehmet Barış Kalkar</title>
    <description>The latest articles on DEV Community by Mehmet Barış Kalkar (@mbaris).</description>
    <link>https://dev.to/mbaris</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%2F690921%2F848609bf-97fb-46e2-9a9d-45b30ad2a1a4.jpeg</url>
      <title>DEV Community: Mehmet Barış Kalkar</title>
      <link>https://dev.to/mbaris</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mbaris"/>
    <language>en</language>
    <item>
      <title>Opinionated Frameworks</title>
      <dc:creator>Mehmet Barış Kalkar</dc:creator>
      <pubDate>Sat, 16 Apr 2022 14:48:56 +0000</pubDate>
      <link>https://dev.to/mbaris/opinionated-frameworks-54ed</link>
      <guid>https://dev.to/mbaris/opinionated-frameworks-54ed</guid>
      <description>&lt;h3&gt;
  
  
  Opinionated
&lt;/h3&gt;

&lt;p&gt;Definition of the word opinionated by merriam-webster is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;firmly or unduly adhering to one's own opinion or to preconceived notions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Opinionated Frameworks
&lt;/h3&gt;

&lt;p&gt;In software development related discussions however, this word is used together with languages, frameworks or tools and it has a more specific meaning.&lt;/p&gt;

&lt;p&gt;An opinionated framework/language has an “intended” or “right” way of doing things.&lt;/p&gt;

&lt;p&gt;Python is considered opinionated because there is a &lt;a href="https://docs.python-guide.org/writing/style/"&gt;“pythonic” way&lt;/a&gt; to solve problems.&lt;/p&gt;

&lt;p&gt;Spring boot, Django, Ruby on Rails and Nestjs are pretty good examples to opinionated web application frameworks. Because they have well accepted ways of implementing things.&lt;br&gt;
For some of the more common encountered issues, they even have default configurations and implementations.&lt;/p&gt;

&lt;p&gt;This does not mean opinionated tools are not flexible. It means, if you use the language, library or the framework correctly, everything should be straightforward and reasonably simple.&lt;/p&gt;

&lt;p&gt;Or in other words, it should “just work” if you are not doing anything crazy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;We have similar frameworks in all languages and there is a good reason it. When we build production ready web applications, we need to think about a lot of common issues.&lt;br&gt;
These are not related to the business solution we want to create but they still take time to implement properly, even if we assume developers have the expertise.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request routing&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Request/Response Serialization/Deserialization&lt;/li&gt;
&lt;li&gt;Database access, possibly with an ORM tool&lt;/li&gt;
&lt;li&gt;Authentication/Authorization&lt;/li&gt;
&lt;li&gt;Request filters&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;Most opinionated frameworks not only have solutions for all these issues, they even have &lt;em&gt;sane defaults&lt;/em&gt;&lt;br&gt;
So we might not need to think about asynchronous logging or Serialization at all during development.&lt;br&gt;
Or when we are implementing authentication, we might use a lot of code from the framework instead of writing it ourselves.&lt;/p&gt;

&lt;p&gt;Similar to how design patterns help the development process, having a shared set of rules and processes to implement functionality can help productivity and maintainability.&lt;br&gt;
This is especially helpful to prevent bike shedding around folder structure, &lt;a href="https://martinfowler.com/bliki/TwoHardThings.html"&gt;naming things&lt;/a&gt; etc.&lt;/p&gt;

&lt;p&gt;Working in multiple projects using the same framework makes switching between them easier and this is a huge boost in productivity if we can leverage it.&lt;/p&gt;

&lt;p&gt;When building services without much experience, using a good framework can teach us about best practices and industry standards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;We have to follow a structure and it might not be ideal for our use case.&lt;/p&gt;

&lt;p&gt;If we leave the &lt;em&gt;golden/happy path&lt;/em&gt; things start to get difficult.&lt;/p&gt;

&lt;p&gt;We might not need all the complexity or the default functionality provided.&lt;/p&gt;

&lt;p&gt;Even &lt;em&gt;sane&lt;/em&gt; defaults might be too magical if we are not aware of them. This is one of the pain points for Spring Boot from my experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Benefits certainly outweigh the cons in my opinion but the decision of using an opinionated vs non-opinionated framework depends a lot on the team size, complexity of the application, number of projects running in parallel and experience of the developers.&lt;br&gt;
In any case, understanding why these frameworks exist and the problems they solve is important before this decision.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Java Records, Lombok and POJOs</title>
      <dc:creator>Mehmet Barış Kalkar</dc:creator>
      <pubDate>Wed, 17 Nov 2021 15:24:54 +0000</pubDate>
      <link>https://dev.to/mbaris/java-records-lombok-and-pojos-18il</link>
      <guid>https://dev.to/mbaris/java-records-lombok-and-pojos-18il</guid>
      <description>&lt;p&gt;For various reasons like carrying or storing data, deserializing/serializing api requests or simply organizing our code base, we use java entities called POJOs or Plain Old Java Objects. They usually have multiple variables with accessor methods and little/no business logic. In most cases, they are immutable and short-lived.&lt;/p&gt;

&lt;h2&gt;
  
  
  POJO
&lt;/h2&gt;

&lt;p&gt;A simple POJO would typically have a public constructor, getters and setters, equals, hashCode and toString methods. Since these classes are used frequently, IDEs have shortcuts to create these methods. So it is actually not a big loss of time to create them. There is still the possibility of forgetting to update an equals or toString method after adding a new field though. Considering how many of these we have, it is still a lot of code to look at and manage.&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;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&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;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

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

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getId&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;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setId&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;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAddress&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;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;o&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="n"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;o&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;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&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;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&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="s"&gt;"User{"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"id='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sc"&gt;'\''&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;", name='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sc"&gt;'\''&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;", address='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sc"&gt;'\''&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="sc"&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;h2&gt;
  
  
  Lombok
&lt;/h2&gt;

&lt;p&gt;Lombok is an annotation processor which works at compile time to add getters, setters and constructors to the code. It is a pretty popular library since java is incredibly verbose compared to other languages and there is always a desire to&lt;br&gt;
have simpler and shorter code. Lombok has more features related to logging, builders, validations etc.&lt;/p&gt;

&lt;p&gt;With this library however, we need to understand that the code we are working on is not syntactically correct until compilation. So we also need a plugin to tell our IDE everything is fine. There are less popular alternatives&lt;br&gt;
like &lt;a href="https://dzone.com/articles/lombok-autovalue-and-immutables"&gt;Immutables and AutoValue&lt;/a&gt; and they use a more natural way of annotation processing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A92hz3NN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f27aohod47xfdpypdmu9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A92hz3NN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f27aohod47xfdpypdmu9.jpeg" alt="This is fine" width="750" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Lombok, we could have the same functionality as the POJO above with a &lt;em&gt;much&lt;/em&gt; shorter definition&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;@Getter&lt;/span&gt;
&lt;span class="nd"&gt;@Setter&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@ToString&lt;/span&gt;
&lt;span class="nd"&gt;@EqualsAndHashCode&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;User&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;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make this even simpler, we can use the &lt;code&gt;@Data&lt;/code&gt; annotation which is equivalent to &lt;code&gt;@Getter&lt;/code&gt; &lt;code&gt;@Setter&lt;/code&gt; &lt;code&gt;@RequiredArgsConstructor&lt;/code&gt; &lt;code&gt;@ToString&lt;/code&gt; &lt;code&gt;@EqualsAndHashCode&lt;/code&gt;. We still need the @AllArgsConstructor to have a constructor with all variables though. Also, we might not want to have &lt;code&gt;@Setter&lt;/code&gt; or a &lt;code&gt;@NoArgsConstructor&lt;/code&gt; in many cases.&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;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&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;User&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;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Records
&lt;/h2&gt;

&lt;p&gt;Records are a relatively new addition to java that solves the same problem without any external libraries, annotation processing or plugins. You can refer to &lt;a href="https://openjdk.java.net/jeps/384"&gt;JEP-384&lt;/a&gt; and &lt;a href="https://openjdk.java.net/jeps/359"&gt;JEP-359&lt;/a&gt; for more context about this feature. Motivation, Goals and Non-Goals are pretty well-defined in these JEPs.&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;record&lt;/span&gt; &lt;span class="nf"&gt;User&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;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this definition, we can create new User instances with the &lt;code&gt;new&lt;/code&gt; keyword like a normal class. Similar to how &lt;code&gt;@Data&lt;/code&gt; from Lombok works, we get public getters for all fields, equals, hashCode and toString methods. However, since every field is final, we do not have setters for records.&lt;/p&gt;

&lt;p&gt;Designed to have a very specific role in java, they have some restrictions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They only have &lt;code&gt;private final&lt;/code&gt; fields for each parameter in their definition, no more instance fields&lt;/li&gt;
&lt;li&gt;They can not extend any other class&lt;/li&gt;
&lt;li&gt;They are implicitly final and cannot be abstract&lt;/li&gt;
&lt;li&gt;They are designed to be immutable, so no setters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While records may not be suitable to work with Spring Data JPA since they are immutable, they work really well as API layer request and responses or messaging DTOs. &lt;br&gt;
They also work really well when you just need them to carry data across layers instead of passing down 5 parameters. Immutability is also an advantage to consider when dealing with records. &lt;/p&gt;
&lt;h3&gt;
  
  
  Compact Constructor
&lt;/h3&gt;

&lt;p&gt;If we want our constructor to do something after initializing the final fields, we can use something called compact constructors. Note that we are not defining a typical constructor, this code block will be running before the actual compiled constructor, and we can use the parameters from the actual constructor itself.&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;record&lt;/span&gt; &lt;span class="nf"&gt;User&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;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;User&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="nc"&gt;StringUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nc"&gt;StringUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ValidationException&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;We can also use annotations like javax validations on records&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;record&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotBlank&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotBlank&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Static Methods in Records
&lt;/h3&gt;

&lt;p&gt;To have more customizations on the record, we can have a static factory method inside the body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;User&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;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think records are really useful in all places where immutability is not a concern. Using a native solution instead of libraries like Lombok is a good move for Java overall.&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Preventing Alert Fatigue</title>
      <dc:creator>Mehmet Barış Kalkar</dc:creator>
      <pubDate>Sun, 07 Nov 2021 19:26:04 +0000</pubDate>
      <link>https://dev.to/mbaris/preventing-alert-fatigue-3f0n</link>
      <guid>https://dev.to/mbaris/preventing-alert-fatigue-3f0n</guid>
      <description>&lt;p&gt;Expectation for software reliability and availability is at an all-time high now. With money and prestige on the line, every application and website wants to avoid downtime while building new things as fast as possible. However, perfect infrastructure or perfect software does not exist, so incidents do happen. &lt;/p&gt;

&lt;p&gt;What we can do is minimizing the impact by making sure we are responding quickly and efficiently. This makes on-call rotations a part of our lives now.&lt;/p&gt;

&lt;p&gt;If structured and compensated correctly, on-call rotations can improve the overall quality and the response time for incidents quite a lot. However, it is not always a positive experience to be on call. One reason for an unpleasant on-call is getting many alerts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alert Fatigue
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Alarm fatigue&lt;/strong&gt; or &lt;strong&gt;alert fatigue&lt;/strong&gt; describes how busy workers become desensitized to safety alerts, and as a result ignore or fail to respond to such warnings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This term did not originate in software, but it is applicable to many industries and works well to describe the problem. It is dangerous for both developers and companies because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when developers start ignoring &lt;em&gt;all&lt;/em&gt; alerts, they also miss or respond later to critical ones&lt;/li&gt;
&lt;li&gt;their productivity suffers&lt;/li&gt;
&lt;li&gt;they are most likely dissatisfied if they are waking up in the middle of the night for alerts multiple times a week&lt;/li&gt;
&lt;li&gt;they are more likely to burn themselves out&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to avoid it?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create Actionable Alerts
&lt;/h3&gt;

&lt;p&gt;Rule #1 in creating effective monitors is having actionable alerts. If you are not going to take any action when you get the alert, you might need to re-evaluate your thresholds or change what you are monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevent Over-Monitoring
&lt;/h3&gt;

&lt;p&gt;We are collecting a lot of metrics from our services, but it does not mean we should create monitors for every single one of them. We should be deliberate while creating more monitors and make sure every alert should be useful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Misconfigured monitoring is a common cause of operational overload. Paging alerts should be aligned with the symptoms that threaten a service’s SLOs. All paging alerts should also be actionable. Low-priority alerts that bother the on-call engineer every hour (or more frequently) disrupt productivity, and the fatigue such alerts induce can also cause serious alerts to be treated with less attention than necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Delay Non-Urgent Notifications
&lt;/h3&gt;

&lt;p&gt;We really do not need to fix every single issue when we notice them. If something can wait until the morning and we know it in advance, delay the notification until working hours. Some examples for this could be problems in non-production environments, temporarily having longer response times from a non-critical service or any other trivial issue.&lt;/p&gt;

&lt;p&gt;Trying to deploy changes at 3AM in the morning, on your own, without any reviewers stresses me out just by thinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up Priorities
&lt;/h3&gt;

&lt;p&gt;Not every alert has the same priority. We can have many alerts and monitors but only the critical ones should wake us up or call us. Some can be just push notifications or informational alerts without any notification which are closed automatically if the situation does not get worse. We can also use different priorities with escalations and notification settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Owners Should Be On-call for their services
&lt;/h3&gt;

&lt;p&gt;Being on call was a sysadmin/ops task traditionally, but now it is the norm for developers to be on-call for the services&lt;br&gt;
they maintain. Ideally, we should only be getting alerts only from services we own.&lt;/p&gt;

&lt;p&gt;This structure helps in multiple ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;since you have more expertise, you are more likely to know what to do&lt;/li&gt;
&lt;li&gt;you do not need to ask questions to other people so you can act quickly when a situation arises&lt;/li&gt;
&lt;li&gt;you feel more responsible for your service&lt;/li&gt;
&lt;li&gt;you can analyze the impact and priority of problems better&lt;/li&gt;
&lt;li&gt;you are more motivated to fix recurring issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This changes according to business domain and company but, we might also consider having on call-rotations for non-engineering teams like business or marketing too.&lt;/p&gt;

&lt;p&gt;In some situations, having an on-call for more than one services might make sense. Not having enough experienced engineers in a team could be one reason for this because being on-call every other week is an even larger problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Incident Runbooks
&lt;/h3&gt;

&lt;p&gt;Having incident runbooks is a good way to reduce stress associated with getting paged. Instead of thinking for a solution, we can follow a list of steps. Creating these runbooks also makes sure we are creating meaningful alerts. Because if we can't think of anything to do when we get the alert, it might be unnecessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Have a good escalation plan
&lt;/h3&gt;

&lt;p&gt;There might be extraordinary cases where we are not available to respond to an alert. Alternatively, we might need help from our teammates to solve a certain issue. In this case, the person or teams we are asking for help should be already clear to us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be comfortable to ask for help
&lt;/h3&gt;

&lt;p&gt;Asking for help should feel natural during incidents. On-call rotations are set up so not everyone is pinged for every single alert. A second person is really useful in most problems because bouncing off ideas or an extra set of eyes helps a lot while solving problems. If the issue actually needs everyone in the team to work on it, they should. This is also a great way to share expertise within teams because incidents are a great source of experience for everyone involved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Have a clean alerts dashboard
&lt;/h3&gt;

&lt;p&gt;Having a clean alerts dashboard is a good indicator for a team which is on top of their alerts and monitors. If you have dozens of open alerts all the time, you might be missing important alerts or ignoring some problems with your service. If having an empty dashboard is the norm, every alert feels important&lt;/p&gt;

</description>
      <category>devops</category>
      <category>monitoring</category>
      <category>sre</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Anatomy of a Dockerfile</title>
      <dc:creator>Mehmet Barış Kalkar</dc:creator>
      <pubDate>Sat, 21 Aug 2021 18:27:36 +0000</pubDate>
      <link>https://dev.to/mbaris/anatomy-of-a-dockerfile-4b4p</link>
      <guid>https://dev.to/mbaris/anatomy-of-a-dockerfile-4b4p</guid>
      <description>&lt;h2&gt;
  
  
  What is a Dockerfile?
&lt;/h2&gt;

&lt;p&gt;Dockerfile is a text document containing commands which can be run in sequence to assemble a docker image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/get-started/02_our_app/"&gt;A sample Dockerfile from the official docs&lt;/a&gt; looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12-alpine&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; python g++ make
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "src/index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why do we need them?
&lt;/h2&gt;

&lt;p&gt;There are millions of images on &lt;a href="https://hub.docker.com/search?q=&amp;amp;type=image"&gt;dockerhub&lt;/a&gt; that we can directly start using with a command like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 &lt;span class="nt"&gt;--name&lt;/span&gt; web nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For various reasons, we may want to customize these base images. Docker images are immutable, so we can't &lt;em&gt;exactly&lt;/em&gt; modify them.&lt;br&gt;
We can technically run a container using an existing image, make some changes on it and then create a &lt;em&gt;new&lt;/em&gt; image with these modifications using the &lt;em&gt;commit&lt;/em&gt; command but there is a better way to accomplish this task &lt;br&gt;
However, before we start modifying images, we need to understand the concept of &lt;a href="https://docs.docker.com/storage/storagedriver/"&gt;layers in docker&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Images, Layers and Containers
&lt;/h3&gt;

&lt;p&gt;Each Docker container consists of a readable and writable layer on top of multiple read only layers.&lt;br&gt;
These read only layers represent instructions in Dockerfiles, and they are deltas on previous layers(similar to git commits)&lt;/p&gt;

&lt;p&gt;Multiple containers can share the underlying layers since they have their own writable/readable layer on top.&lt;br&gt;
The readable and writable layer is a thin layer which has a lifespan associated with the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; tiangolo/uvicorn-gunicorn-fastapi:python3.7&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mehmet Baris Kalkar"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; version="1.1"&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast api 
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; fast:api&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GREETING="hola"&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./app /project/app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /project&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8090&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8090"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we create a container from this same dockerfile, we will see a log similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;1/4] FROM docker.io/tiangolo/uvicorn-gunicorn-fastapi:python3.7@sha256:a0e0188a485fd8c232d8774ae4680d3b834f95dd2deccdb0211ce71cfd778b97
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;internal] load build context
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring context: 56B
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;2/4] RUN addgroup api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast api
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;3/4] COPY ./app /project/app 
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;4/4] WORKDIR /project 
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; exporting to image 
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; exporting layers 
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; writing image sha256:3cef1a7b7ddc037fa375a1fb37daa907bc31031fedb4142b98e98e582c0bead5
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; naming to docker.io/library/fastapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One important thing to understand is &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache"&gt;how these instructions are cached&lt;/a&gt;.&lt;br&gt;
The result of some commands like FROM, COPY/ADD, RUN and WORKDIR can be cached.&lt;/p&gt;

&lt;p&gt;Cached instructions are marked in the build command. If we build the same image by changing only the WORKDIR instruction to project2, we would see something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; CACHED &lt;span class="o"&gt;[&lt;/span&gt;1/4] FROM docker.io/tiangolo/uvicorn-gunicorn-fastapi:python3.7@sha256:a0e0188a485fd8c232d8774ae4680d3b834f95dd2deccdb0211ce71cfd778b97
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;internal] load build context
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring context: 56B
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; CACHED &lt;span class="o"&gt;[&lt;/span&gt;2/4] RUN addgroup api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast api
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; CACHED &lt;span class="o"&gt;[&lt;/span&gt;3/4] COPY ./app /project/app
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;4/4] WORKDIR /project2
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; exporting to image
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; exporting layers
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; writing image sha256:fe482845750cf79708d1a6cc107578e76bd843f92fb3092d636180547b32b897
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; naming to docker.io/library/fastapi   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at this Dockerfile line by line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Optional) &lt;em&gt;&lt;a href="https://docs.docker.com/engine/reference/builder/#syntax"&gt;syntax&lt;/a&gt;&lt;/em&gt; is only enabled if we are building the image with &lt;a href="https://docs.docker.com/engine/reference/builder/#buildkit"&gt;BuildKit&lt;/a&gt;&lt;br&gt;
In this line, we can inform the Dockerfile builder which syntax to use while parsing the Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; tiangolo/uvicorn-gunicorn-fastapi:python3.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;FROM&lt;/em&gt; instruction is used to set the base image that we are going to use. &lt;br&gt;
This should always be the first instruction in a Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mehmet Baris Kalkar"&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; version="1.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;LABEL&lt;/em&gt; instructions are used to add metadata to images.&lt;/p&gt;

&lt;p&gt;Side note, There used to be a MAINTAINER instruction in the past, but it is deprecated now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser fast api 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;RUN&lt;/em&gt; instruction is used to execute commands in a new layer on top of the current image and commit changes.&lt;br&gt;
Following steps will use the new image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; fast:api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;USER&lt;/em&gt; instruction sets the user and group for the following steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GREETING="hola"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ENV&lt;/em&gt; is used to add environment variables to the container. This variable can be used in the following steps during build as well.&lt;br&gt;
If we want to use a variable in only a single command and not in the image, we can define use the RUN command with a variable instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nv"&gt;LOCUST_LOCUSTFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;custom_locustfile.py locust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./app /project/app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;COPY [--chown=:] ... &lt;/em&gt; copies files from source and adds it to the file system of the container&lt;br&gt;
Target path is always relative to the working directory.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ADD&lt;/em&gt; command also has a similar function, but it can also be used to fetch files from a remote URL or extract tar files. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy"&gt;It is preferred to use COPY&lt;/a&gt; &lt;br&gt;
over add because COPY is a more transparent and simple instruction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;WORKDIR&lt;/em&gt; Sets the working directory to run instructions like CMD, RUN, ENTRYPOINT and COPY after this step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8090&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;EXPOSE&lt;/em&gt; is an informational instruction. It does not actually publish any ports, but it is used as a documentation to let &lt;br&gt;
users know which ports should be published to use the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8090"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;CMD&lt;/em&gt; is the instruction to define the command you want to execute when run a container from an image. &lt;br&gt;
It is possible to override this command while actually running the image, so it acts as a default. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;ENTRYPOINT&lt;/em&gt; and &lt;em&gt;CMD&lt;/em&gt; are similar commands, &lt;a href="https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/"&gt;the differences are explained here pretty well&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;VOLUME&lt;/em&gt; command is used to create mounting points within the container. &lt;br&gt;
We can use these volumes to &lt;a href="https://docs.docker.com/storage/volumes/"&gt;share files between containers or the native host&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
