<?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: Richard Lenkovits</title>
    <description>The latest articles on DEV Community by Richard Lenkovits (@pencillr).</description>
    <link>https://dev.to/pencillr</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%2F26825%2Fc9d06288-b195-4eed-b820-d45fc943518d.jpg</url>
      <title>DEV Community: Richard Lenkovits</title>
      <link>https://dev.to/pencillr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pencillr"/>
    <language>en</language>
    <item>
      <title>Simple bash loading animation</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Thu, 27 Jul 2023 09:44:53 +0000</pubDate>
      <link>https://dev.to/pencillr/simple-bash-loading-animation-4i1o</link>
      <guid>https://dev.to/pencillr/simple-bash-loading-animation-4i1o</guid>
      <description>&lt;p&gt;I was looking for a simple way to achieve a basic &lt;strong&gt;load icon that ticks after a piece of text&lt;/strong&gt; in bash, but there was noting I could just easily copy paste. Now I'll provide one for you, no shenanigans, no messing around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short story
&lt;/h2&gt;

&lt;p&gt;I've found this one, &lt;a href="https://github.com/Silejonu/bash_loading_animations" rel="noopener noreferrer"&gt;Silejonu's solution on Github&lt;/a&gt; but this is rather a module than something you can copy paste, and sometimes you don't want to add whole dependencies, just a piece of logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  So here it is:
&lt;/h3&gt;


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

&lt;p&gt;&lt;span class="k"&gt;function &lt;/span&gt;loading_icon&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;load_interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;br&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;loading_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;br&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;elapsed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;br&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;loading_animation&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s1"&gt;'—'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'|'&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="nb"&amp;gt;echo&amp;lt;/span&amp;gt; &amp;lt;span class="nt"&amp;gt;-n&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nv"&amp;gt;loading_message&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt; "&amp;lt;/span&amp;gt;

&amp;lt;span class="c"&amp;gt;# This part is to make the cursor not blink&amp;lt;/span&amp;gt;
&amp;lt;span class="c"&amp;gt;# on top of the animation while it lasts&amp;lt;/span&amp;gt;
tput civis
&amp;lt;span class="nb"&amp;gt;trap&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"tput cnorm"&amp;lt;/span&amp;gt; EXIT
&amp;lt;span class="k"&amp;gt;while&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;[&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nv"&amp;gt;load_interval&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt; &amp;lt;span class="nt"&amp;gt;-ne&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nv"&amp;gt;elapsed&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;;&amp;lt;/span&amp;gt; &amp;lt;span class="k"&amp;gt;do
    for &amp;lt;/span&amp;gt;frame &amp;lt;span class="k"&amp;gt;in&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nv"&amp;gt;loading_animation&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;[@]&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt; &amp;lt;span class="p"&amp;gt;;&amp;lt;/span&amp;gt; &amp;lt;span class="k"&amp;gt;do
        &amp;lt;/span&amp;gt;&amp;lt;span class="nb"&amp;gt;printf&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"%s&amp;lt;/span&amp;gt;&amp;lt;span class="se"&amp;gt;\b&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nv"&amp;gt;frame&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;
        &amp;lt;span class="nb"&amp;gt;sleep &amp;lt;/span&amp;gt;0.25
    &amp;lt;span class="k"&amp;gt;done
    &amp;lt;/span&amp;gt;&amp;lt;span class="nv"&amp;gt;elapsed&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;=&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;$((&amp;lt;/span&amp;gt; elapsed &amp;lt;span class="o"&amp;gt;+&amp;lt;/span&amp;gt; &amp;lt;span class="m"&amp;gt;1&amp;lt;/span&amp;gt; &amp;lt;span class="k"&amp;gt;))&amp;lt;/span&amp;gt;
&amp;lt;span class="k"&amp;gt;done
&amp;lt;/span&amp;gt;&amp;lt;span class="nb"&amp;gt;printf&amp;lt;/span&amp;gt; &amp;lt;span class="s2"&amp;gt;" &amp;lt;/span&amp;gt;&amp;lt;span class="se"&amp;gt;\b\n&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;"&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;loading_icon 60 &lt;span class="s2"&gt;"I'm loading!"&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  And here's what it looks like:&lt;br&gt;
&lt;/h3&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%2Fwwoj4pjjtpclfic05q8z.gif" 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%2Fwwoj4pjjtpclfic05q8z.gif" alt="bash loading animation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Shows a given &lt;code&gt;loading_message&lt;/code&gt; and after it a small loading icon for the provided &lt;code&gt;load_interval&lt;/code&gt; seconds.&lt;/li&gt;
&lt;li&gt;After the provided time elapsed the last character of the loading icon is erased and a new line is started (this can be changed by updating &lt;code&gt;printf " \b\n"&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;You can get more animation ideas from &lt;a href="https://github.com/Silejonu/bash_loading_animations/blob/main/bash_loading_animations.sh" rel="noopener noreferrer"&gt;Silejonu, bash_loading_animations file&lt;/a&gt;, all you have to do is to replace the &lt;code&gt;loading_animation&lt;/code&gt; variable in the script (don't forget to remove the first element, the interval number).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoy!&lt;/strong&gt; ^^&lt;/p&gt;

</description>
      <category>bash</category>
      <category>terminal</category>
      <category>devops</category>
      <category>development</category>
    </item>
    <item>
      <title>Why common CI ownership is a myth at large companies</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Wed, 07 Jun 2023 13:44:59 +0000</pubDate>
      <link>https://dev.to/pencillr/why-common-ci-ownership-is-a-myth-at-large-companies-hgg</link>
      <guid>https://dev.to/pencillr/why-common-ci-ownership-is-a-myth-at-large-companies-hgg</guid>
      <description>&lt;p&gt;People need to keep their environment and infrastructure in shape in order to be productive. You might be a farmer who primarily grows corn, but you also must build a pavement between your house and your farm so you can get to work, and mow the lawn next to it so it doesn't grow over. You have to change your lightbulbs if they go out so you find your way home, and maybe take out the trash every once in a while.&lt;/p&gt;

&lt;p&gt;The situation is similar though a tad bit more complicated for smaller communities — like a group of neighbors on a spot of land, or for the inhabitants of a smaller residential building. Somebody has to mop the floors once in a while, clean the common areas and fix busted fittings.&lt;/p&gt;

&lt;p&gt;The issues come when we scale things up beyond that — see something like a small village, or a city. In a residential building it's easy to see why it's everybody's problem that the elevator stopped working. In a village however you may find it hard to justify why you should care, that a bench broke at the bus stop when you're only using the train. The village has a lot of people, it's easy for you to hide and shake the responsibility, which you can easily do without caring — until a later time the bench brakes at the train station.&lt;/p&gt;

&lt;p&gt;At a small software company when the build breaks, or the servers go down you won't just lean back in your chair saying it's not your problem. Come on, there are like three developers, one of those is on holiday. That leaves the two of you, both of your work being blocked. A small company is like a residential building.&lt;/p&gt;

&lt;p&gt;A large company is however more like a country. In a country when you notice a busted street lamp you won't start fixing it. That's why you pay tax and have specialized teams to deal with these issues.&lt;br&gt;
When an ansible playbook that should configure a VM fails somewhere in an automated setup script for tests you cannot just expect a guy from backend development to start fixing it, when he's busy to deliver for a deadline.&lt;/p&gt;

&lt;p&gt;I saw companies trying to find ways to have developers acquire a &lt;em&gt;"CI (or) DevOps mindset"&lt;/em&gt; so that they keep track of the whole verification chain, develop it, and also keep track of their changes through the highly complex pipelines and fix it if needed. On top of this, integration and verification pipelines become their own product at large companies due to multi-layered release bureaucracy and the highly complex nature of the products that are being developed.&lt;/p&gt;

&lt;p&gt;I know that it sounds tempting to imagine that your developers will reach targets effectively and also develop and maintain your verification pipelines at the same time but it's a wild-goose chase.&lt;br&gt;
You simply &lt;em&gt;cannot spare&lt;/em&gt; specialized DevOps teams. Unless you're fine with your citizens fixing street lamps for themselves with however dingy ways they can manage.&lt;/p&gt;

</description>
      <category>ci</category>
      <category>devops</category>
      <category>career</category>
      <category>development</category>
    </item>
    <item>
      <title>Test Ansible playbooks using Docker</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Tue, 21 Mar 2023 21:28:17 +0000</pubDate>
      <link>https://dev.to/pencillr/test-ansible-playbooks-using-docker-ci0</link>
      <guid>https://dev.to/pencillr/test-ansible-playbooks-using-docker-ci0</guid>
      <description>&lt;p&gt;Okay so this is what we're going to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up an ssh accessible Ubuntu container.&lt;/li&gt;
&lt;li&gt;Running an Ansible playbook against it to &lt;em&gt;test&lt;/em&gt; that playbook.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Come again?
&lt;/h2&gt;

&lt;p&gt;I know it's weird, hear me out.&lt;/p&gt;

&lt;p&gt;Here's the scenario that we're trying to tackle. Imagine that:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; You have Ansible playbooks to configure certain machines.&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; You run these playbooks once during the initial setup and forget about them.&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; A lot of time passes.&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; Later a developer needs to add a package or some change to the given host or host group.&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; They should update the ansible playbook and run it, but they're afraid they'll break the environment. Who knows when were those playbooks last run? Maybe they even have an invalid description of the current system. As a result the developer either: &lt;strong&gt;A.:&lt;/strong&gt; Just does the changes by hand and best case, &lt;strong&gt;B.:&lt;/strong&gt; ...updates the playbooks as well. But who know if it's a correct update.&lt;/p&gt;

&lt;p&gt;This is how playbooks &lt;em&gt;decay&lt;/em&gt; - at least in our environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0itnw58djjrjo4lwrlo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0itnw58djjrjo4lwrlo.gif" alt="People playing a clutch Jenga game." width="384" height="480"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why such a basic validity check could be of good use
&lt;/h2&gt;

&lt;p&gt;Having some simple tests could solve our issues, and provide some constant feedback about the playbooks' validity. But how do you test Ansible playbooks (other than lint them)? Playbooks are just ordered instructions describing a &lt;em&gt;desired state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Still, they could be faulty - it's easy to make mistakes when you're trying to translate your desired configuration steps into Ansible tasks. You may mess up a task, forget a necessary parameter on a module, maybe you try to install something for which you forget to provide it's prerequisites.&lt;/p&gt;

&lt;p&gt;Preferably we want some tests which can &lt;strong&gt;run our playbooks against an ephemeral environment&lt;/strong&gt; to see if they're -well- &lt;em&gt;runnable&lt;/em&gt;. This is where &lt;strong&gt;docker&lt;/strong&gt; comes into the picture. In docker you can test &lt;em&gt;most of the things&lt;/em&gt; that you'd want to do with Ansible. Obviously for more complicated playbooks this might not be a good solution.&lt;/p&gt;


&lt;h2&gt;
  
  
  Test setup
&lt;/h2&gt;

&lt;p&gt;This is how our small demo directory -with which we'll make our point- looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Dockerfile
├── ansible.cfg
├── machine-setup.yml
└── setup-container.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Example Playbook and config
&lt;/h3&gt;

&lt;p&gt;There's a very simple playbook &lt;code&gt;machine-setup.yml&lt;/code&gt;, that sets up some packages on the host group called &lt;code&gt;target_group&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# yamllint disable rule:line-length&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Machine&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;target_group&lt;/span&gt;
  &lt;span class="na"&gt;gather_facts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install requirements&lt;/span&gt;
      &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;pkg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;flake8&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pylint&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3-pip&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
      &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task_result&lt;/span&gt;
      &lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;not task_result.failed&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We provide some necessary Ansible config in a cfg file &lt;code&gt;ansible.cfg&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[defaults]
# Avoid host key checking - to to run without interaction.
host_key_checking = False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Test Container
&lt;/h3&gt;

&lt;p&gt;We create a &lt;code&gt;Dockerfile&lt;/code&gt; too which describes for us an ssh accessible ubuntu 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="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:latest&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; USER=${USER}&lt;/span&gt;

&lt;span class="c"&gt;# Add sudo and openssh-server&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DEBIAN_FRONTEND=noninteractive&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class="nb"&gt;install &lt;/span&gt;openssh-server &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Setup running user on the container with sudo rights and&lt;/span&gt;
&lt;span class="c"&gt;# password-less ssh login&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;adduser &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;sudo&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ALL=(ALL) NOPASSWD: ALL"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/sudoers.d/sudoers

&lt;span class="c"&gt;# As the user setup the ssh identity using the key in the tmp folder&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; "${USER}"&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/.ssh
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 700 ~/.ssh
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=${USER}:sudo id_rsa.pub /home/${USER}/.ssh/id_rsa.pub&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa.pub &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/authorized_keys
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;644 ~/.ssh/id_rsa.pub
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;644 ~/.ssh/authorized_keys

&lt;span class="c"&gt;# start ssh with port exposed&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;service ssh start

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 22&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/usr/sbin/sshd", "-D"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Testing Script
&lt;/h3&gt;

&lt;p&gt;Our script will start this container, run the playbook against it and clean up everything. Let's see it step by step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We make sure to have a unique container name, and a path to our assets.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt; /dev/urandom &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; &lt;span class="s1"&gt;'a-z0-9'&lt;/span&gt; | &lt;span class="nb"&gt;fold&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 5 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;:
&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"compute-node-sim-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;readlink&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We add a function to create &lt;strong&gt;temporary directory&lt;/strong&gt; to store our temporary assets (like the inventory and the ssh id).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;setup_tempdir&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;--directory&lt;/span&gt; &lt;span class="s2"&gt;"/tmp/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;.XXXXXXXX&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;export &lt;/span&gt;TEMP_DIR
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We setup a &lt;code&gt;cleanup&lt;/code&gt; function which will be able to clean up the temporary folder and the container as well.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;cleanup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;container_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker inspect &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{.Id}}"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;:&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;container_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning up container &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;container_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning up tepdir &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We need a function that will create ssh identities so Ansible can access the container through ssh. During &lt;code&gt;docker build&lt;/code&gt; these will be added inside the container by a &lt;code&gt;COPY&lt;/code&gt; step (see above in the Dockerfile).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;create_temporary_ssh_id&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    ssh-keygen &lt;span class="nt"&gt;-b&lt;/span&gt; 2048 &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@email.com"&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/id_rsa"&lt;/span&gt; &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/id_rsa"&lt;/span&gt;
    &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/id_rsa.pub"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We build and start the container with this function - providing the &lt;code&gt;TEMP_DIR&lt;/code&gt; as it's context. We figure out the container's address for ssh.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;start_container&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    docker build &lt;span class="nt"&gt;--tag&lt;/span&gt; &lt;span class="s2"&gt;"compute-node-sim"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--build-arg&lt;/span&gt; USER &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--file&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Dockerfile"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"compute-node-sim"&lt;/span&gt;
    &lt;span class="nv"&gt;CONTAINER_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker inspect &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;export &lt;/span&gt;CONTAINER_ADDR
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We create a &lt;strong&gt;test inventory&lt;/strong&gt; which has our &lt;code&gt;target_group&lt;/code&gt; containing only the container by it's address we fetched above. We also add the ssh identity to be used when running the playbook.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;setup_test_inventory&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;TEMP_INVENTORY_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/hosts"&lt;/span&gt;

    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_INVENTORY_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOL&lt;/span&gt;&lt;span class="sh"&gt;
[target_group]
&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_ADDR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;:22
[target_group:vars]
ansible_ssh_private_key_file=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/id_rsa
&lt;/span&gt;&lt;span class="no"&gt;EOL
&lt;/span&gt;    &lt;span class="nb"&gt;export &lt;/span&gt;TEMP_INVENTORY_FILE
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We add the playbook runner function. It will run against our temporary inventory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;run_ansible_playbook&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;ANSIBLE_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/ansible.cfg"&lt;/span&gt;
    ansible-playbook &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_INVENTORY_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-vvv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/machine-setup.yml"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now we run it all:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setup_tempdir
&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup EXIT
&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup ERR
create_temporary_ssh_id
start_container
setup_test_inventory
run_ansible_playbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Full script for reference:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt; /dev/urandom &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; &lt;span class="s1"&gt;'a-z0-9'&lt;/span&gt; | &lt;span class="nb"&gt;fold&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 5 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;:
&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"compute-node-sim-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;readlink&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;cleanup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;container_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker inspect &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{.Id}}"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;:&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;container_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning up container &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;container_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning up tepdir &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;setup_tempdir&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;--directory&lt;/span&gt; &lt;span class="s2"&gt;"/tmp/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;.XXXXXXXX&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;export &lt;/span&gt;TEMP_DIR
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;create_temporary_ssh_id&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    ssh-keygen &lt;span class="nt"&gt;-b&lt;/span&gt; 2048 &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@email.com"&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/id_rsa"&lt;/span&gt; &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/id_rsa"&lt;/span&gt;
    &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/id_rsa.pub"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;start_container&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    docker build &lt;span class="nt"&gt;--tag&lt;/span&gt; &lt;span class="s2"&gt;"compute-node-sim"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--build-arg&lt;/span&gt; USER &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--file&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Dockerfile"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"compute-node-sim"&lt;/span&gt;
    &lt;span class="nv"&gt;CONTAINER_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker inspect &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;export &lt;/span&gt;CONTAINER_ADDR
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;setup_test_inventory&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;TEMP_INVENTORY_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/hosts"&lt;/span&gt;

    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_INVENTORY_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOL&lt;/span&gt;&lt;span class="sh"&gt;
[target_group]
&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_ADDR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;:22
[target_group:vars]
ansible_ssh_private_key_file=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/id_rsa
&lt;/span&gt;&lt;span class="no"&gt;EOL
&lt;/span&gt;    &lt;span class="nb"&gt;export &lt;/span&gt;TEMP_INVENTORY_FILE
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;run_ansible_playbook&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;ANSIBLE_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/ansible.cfg"&lt;/span&gt;
    ansible-playbook &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEMP_INVENTORY_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-vvv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/machine-setup.yml"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

setup_tempdir
&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup EXIT
&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup ERR
create_temporary_ssh_id
start_container
setup_test_inventory
run_ansible_playbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope you found something useful here!&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>docker</category>
      <category>ci</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to upgrade your PC's RAM</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Wed, 30 Mar 2022 15:16:49 +0000</pubDate>
      <link>https://dev.to/pencillr/how-to-upgrade-your-pcs-ram-gbk</link>
      <guid>https://dev.to/pencillr/how-to-upgrade-your-pcs-ram-gbk</guid>
      <description>&lt;h2&gt;
  
  
  Short preface, no BS
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Howdy!&lt;/em&gt;&lt;br&gt;
You probably ended up here because you &lt;del&gt;like to have 50 chrome tabs open&lt;/del&gt; need to upgrade your PC's RAM and you want to do it right. I just upgraded RAM in my PC so let me spare you all the time I spent to figure out all the technical stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  In this article we will:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; See how to get the memory specs of your system.&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; How to use those specs to select RAM suitable for upgrade.&lt;/p&gt;

&lt;p&gt;Let's go!&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%2Fztbj04v9e29lfwatcyg6.gif" 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%2Fztbj04v9e29lfwatcyg6.gif" alt="Chrome needs a lot of memory gif"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What factors do I have to consider?
&lt;/h2&gt;

&lt;p&gt;In order to make sure the RAM you buy will work, you'll have to consider the following factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;RAM capacity&lt;/strong&gt; of your motherboard?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form factor&lt;/strong&gt;, &lt;strong&gt;type&lt;/strong&gt;, &lt;strong&gt;speeds&lt;/strong&gt;, and &lt;strong&gt;voltages&lt;/strong&gt; supported by your motherboard?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility&lt;/strong&gt; with your &lt;strong&gt;current RAM&lt;/strong&gt;? (&lt;em&gt;Type&lt;/em&gt;, &lt;em&gt;speed&lt;/em&gt;, &lt;em&gt;voltage&lt;/em&gt; and &lt;em&gt;CL&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;And finally &lt;strong&gt;how much RAM&lt;/strong&gt; do you actually need?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see how to figure out all these specs and select RAM with the correct parameters!&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  Assembling a new PC?
&lt;/h2&gt;

&lt;p&gt;Normally with a few commands you can figure out your memory specs. However if you're just assembling your PC you obviously won't be able to run commands. This case, you can go to the site of your motherboard's manufacturer and see what it supports.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.msi.com/Motherboard/PRO-Z690-A-DDR4/Specification" rel="noopener noreferrer"&gt;Here's an example of an MSI Motherboard&lt;/a&gt;'s details. In the &lt;em&gt;DDR4 MEMORY&lt;/em&gt; row you can see all the frequencies supported by the manufacturer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyhow, let's get this done bois' and girls!&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%2Fuj1n0j936dm1lt0wauee.gif" 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%2Fuj1n0j936dm1lt0wauee.gif" alt="High end pc running gif"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Get RAM specs for Windows:
&lt;/h2&gt;

&lt;p&gt;Start a &lt;strong&gt;Command Prompt&lt;/strong&gt;, make sure you &lt;strong&gt;run as administrator&lt;/strong&gt;, then execute the following commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Get memory details&lt;/strong&gt; with the &lt;code&gt;wmic memorychip&lt;/code&gt; command. This will print parameters separately for &lt;em&gt;each&lt;/em&gt; RAM module installed - so the number of printed lines will tell you how many RAM modules you have installed.
```
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;wmic memorychip get memorytype, capacity, speed, formfactor, manufacturer, configuredvoltage&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Then **get the total number of memory slots** with the `wmic memphysical` command. Then deduct the number of printouts from the previous command from this number to get how many free slots you have on your motherboard. (Or just open your PC and see how many open slots you have left! You can also install the [Speccy](https://www.ccleaner.com/speccy) app to figure this out.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;wmic memphysical get memorydevices&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; ### Understanding the printouts:
&amp;gt; - *Manufacturer* is just the manufacturer.
&amp;gt; - *Capacity* will be the RAM capacity in *bytes* (google will convert it to GB in one search).
&amp;gt; - *Speed* is the RAM speed/frequency in *MHz*.
&amp;gt; - *ConfiguredVoltage* is the configured voltage for this device, in millivolts.
&amp;gt; - *MemoryType* will be a number between 0-26.
&amp;gt; - *Formfactor* will also be a number between 0-23.

&amp;gt; To figure out what these numbers mean check the official windows documentation for [Win32_PhysicalMemory](https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-physicalmemory) and search *Memorytipe* and *Formfactor*.
&amp;gt; Here's a short version though: *Formfactor* 8 and 12 will be the most common, where **8 means DIMM** (Dual in-line Memory Module - the long one that goes to PC's) and **12 is SO-DIMM** (the short one for laptops).
&amp;gt; Regarding *MemoryType*, number **24** (**DDR3**) and **26** (**DDR4**) will be the most common.

## Get RAM specs for Linux:
If you're a Linux user you've probably figured this out already but if not, you can use `dmidecode` to find all the information about your RAM:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sudo apt install dmidecode&lt;br&gt;
sudo dmidecode --type 17&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cool now we have all the specs! Let's see why they're important!
___
## Memory parameters per each
Let's see why each parameter matters and how to do the upgrade keeping these in mind.

### Motherboard Limits
&amp;gt; Swap or add.

You can put as many RAM modules in your machine as your motherboard allows, but the general performance will be a little bit lower the more modules you install. That's why it's better to have fewer, more powerful RAM modules than many with smaller capacity. Modern laptops and PCs usually have at least 2 memory slots.

When you upgrade you basically have 2 options: you swap or you add. If you decide to add a new memory module next to the current one make sure that all the specs align (see bellow).

Also in most machines there's a primary memory slot. It's generally better to put the module with the most capacity to the primary slot.
One thing to mention for older systems: 32bit systems can only utilize 4GB memory max. If you have a 32 bit system every memory beyond 4 gigs is wasted. 

### Manufacturer
&amp;gt; Buy modules from the same manufacturer.

It is said that memory blocks from the same manufacturer generally work better together. If you're installing an upgrade, or you're buying more RAM modules, try to make sure you **buy modules from the same manufacturer**.

### Capacity
&amp;gt; 8GB min, 16GB for work, 32GB+ for high end gaming.

This is the simplest one. Capacity is cumulative (it adds up). Also, you can **freely mix** RAM with different capacities (for example 8GB+4GB).

Question is how much memory you really need? At the writing of this article **8GB** RAM can be enough to run a PC with Windows 10, if all you do is browsing the web and reading emails.
If you want to be safe **16GB** is a good amount to do web development, or anything that requires many browser tabs to be open.
For high end gaming you should go **32GB** or more.

### Speed/frequency
&amp;gt; Faster is better but check motherboard compatibility - or buy the same speed your current memory has!

Generally faster speeds are better, but when doing an upgrade your goal is to **install modules that have the same speed!** (If frequencies differ, the slower can actually slow the better one down to make sure they're in sync.) Also make sure your motherboard supports the frequency of your RAM.

### Voltage
&amp;gt; Buy low voltage, or the same voltage as your current RAM.

There can be cases when your motherboard will not be able to operate your RAM if it requires more Voltage than what the motherboard provides. This can usually be set in the BIOS, but to avoid inconveniences make sure to buy the same voltage that your current memory has. Also lower voltage is generally better, and more cost effective.

### Memory Type
Easy. Buy what your motherboard supports/what you currently have (DDR3/4/5)

### Form Factor
Same. Buy the supported type (DIMM/SO-DIMM).

### CAS Latency
&amp;gt; Select the lowest latency or buy the same CL as your current RAM.

CAS Latency, or the CL number is a bit more complicated. You should generally **install modules with the same CAS Latency**! But it's not that simple to figure out what your system currently has. Here are some ways to find out your current RAM CL:
- Search the manufacturer's site, with your serial number. Here's how you get your serial number:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;wmic memorychip get serialnumber, manufacturer&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Install [Speccy](https://www.ccleaner.com/speccy) app and check it there.
- Open your machine and check on the RAM sticker (it may or may not have the CL number on it).

## Summary
&amp;gt; If there's more than one RAM module in a machine the following parameters should be aligned: **manufacturer, frequency, CL, voltage**.

&amp;gt; **Form factor, type, and compatible frequencies** are specified by the motherboard manufacturer.

![memory install](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tmori15gfdexvpb30red.gif)

## Install and Check!
If you've got the RAM that fits all the requirements, all you have to do is to **shut your machine down, make sure it's not plugged in and battery is removed**, then install the RAM.

After restarting your machine you can check if your new memory block is operated properly by your system.

### Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;systeminfo | findstr /C:"Total Physical Memory"&lt;br&gt;
wmic memorychip get capacity&lt;/p&gt;



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

&lt;/div&gt;



&lt;p&gt;free -m&lt;br&gt;
sudo dmidecode -t 17&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Also keep in mind: if everything should be okay but the RAM is not working, it can easily be a *faulty/broken* module. It happened to me before.

**Enjoy your upgraded RAM!**
![plusone](https://thepracticaldev.s3.amazonaws.com/i/ypvzafveynm5q1njmrs3.gif)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>hardware</category>
    </item>
    <item>
      <title>How to realize your client's random app idea</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Tue, 07 Jul 2020 19:18:36 +0000</pubDate>
      <link>https://dev.to/pencillr/how-to-realize-your-client-s-random-app-idea-33ha</link>
      <guid>https://dev.to/pencillr/how-to-realize-your-client-s-random-app-idea-33ha</guid>
      <description>&lt;h1&gt;
  
  
  "So you're a software developer? You know I've got this app idea..."
&lt;/h1&gt;

&lt;p&gt;Sounds familiar?&lt;/p&gt;

&lt;p&gt;I think software developers can all relate to this situation. Everybody has random app ideas, &lt;em&gt;especially your family and friends&lt;/em&gt; when they realize that you've got what it takes.&lt;br&gt;
On the other hand, we developers are not devoid of ideas either - it's just we know the &lt;strong&gt;market&lt;/strong&gt; (&lt;em&gt;which is saturated&lt;/em&gt;) and the &lt;strong&gt;process&lt;/strong&gt; (&lt;em&gt;which is whacking&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;And I'm not talking about coding. Hell, &lt;strong&gt;that's actually the fun part&lt;/strong&gt;! - after all the work you have to put into consolidating business logic, creating UI/UX design, user workflows, database schema, etc.&lt;/p&gt;

&lt;p&gt;Luckily we can usually control our friends' desires - but let me paint you a &lt;em&gt;different picture.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's the same thing but with a twist:&lt;/p&gt;

&lt;h1&gt;
  
  
  "I've got this app idea... &lt;strong&gt;And I'll pay you to do it."&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;OK&lt;/strong&gt;. You might be asking - that’s just the tip of the iceberg, &lt;strong&gt;what are the variables?&lt;/strong&gt; &lt;em&gt;Money&lt;/em&gt;, &lt;em&gt;complexity&lt;/em&gt;, &lt;em&gt;platforms&lt;/em&gt;, who are you going to work with?&lt;br&gt;
Bear with me, because I’m going to show you &lt;em&gt;how I tackled this challenge!&lt;/em&gt; I hope my example will help to explain a few things.&lt;/p&gt;

&lt;p&gt;Here's the story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idea meets me
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/KENUDmJeWHbusfvmkP/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/KENUDmJeWHbusfvmkP/giphy.gif" alt="app idea meme" width="480" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Truth be told I count myself extremely lucky.&lt;br&gt;
It was a &lt;em&gt;small design studio&lt;/em&gt; who first found me with this kind of request and there were &lt;strong&gt;extenuating circumstances&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. The application started as a proof-of-concept thing.
&lt;/h4&gt;

&lt;p&gt;They planned to iterate on it, trying out ideas during development, so nothing was set in stone.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. I had a lot of freedom.
&lt;/h4&gt;

&lt;p&gt;Which is a blessing and a curse as well. A blessing because I had a chance to try out new stuff, experiment, and learn. I'll elaborate on the curse later...&lt;/p&gt;

&lt;h4&gt;
  
  
  3. The app was not going to go full-public.
&lt;/h4&gt;

&lt;p&gt;It was planned to be used only between co-working companies. No huge responsibilities, or significant business security concerns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just some details. This was a full-stack web app (&lt;a href="https://www.geeksforgeeks.org/what-is-pern-stack/"&gt;PERN stack&lt;/a&gt;), with user authentication, separate admin/user interfaces and artifact management - consequently involving a database and storage service.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All the above meant that I had space to learn, improve, and &lt;strong&gt;make mistakes&lt;/strong&gt;, while being paid for it.&lt;br&gt;
Here’s the real kicker though: &lt;strong&gt;for me, it would have worth it even without the money - just for the experience.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Idea meets technology
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/Pu5F5t64WNKYE/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/Pu5F5t64WNKYE/giphy.gif" alt="robot gif from series" width="480" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first bumps along the road came when I realized that my client's app idea was as &lt;strong&gt;undeveloped&lt;/strong&gt; as any random idea, people usually come up with. They could describe the apps main purpose, plus they had some design sketches, but that's about it. &lt;em&gt;A good old idea&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No admin/user interface or workflow design&lt;/strong&gt; - basically no ideas on how admins should be able to configure user privileges and manage data. Literally nothing to help me figure out the database schema and the supported operations.&lt;/li&gt;
&lt;li&gt;The wanted to manage ambiguous artifact types.&lt;/li&gt;
&lt;li&gt;Also, they had super flexible role-based access management expectations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where &lt;em&gt;freedom can become a burden&lt;/em&gt; because you end up to be the &lt;em&gt;expert&lt;/em&gt; who is expected to bring the &lt;strong&gt;best of all worlds&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Find viable, sustainable, and scalable technical solutions...
&lt;/h4&gt;

&lt;h4&gt;
  
  
  2. ...but also don't steer to far from customer expectations...
&lt;/h4&gt;

&lt;h4&gt;
  
  
  3. ...while writing super flexible code to be able to redesign on a whim.
&lt;/h4&gt;

&lt;p&gt;The solution for me was twofold: &lt;em&gt;asking the right questions&lt;/em&gt;, and &lt;em&gt;managing the product&lt;/em&gt; responsibly. Let me explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask the right questions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/8RuJ23GPbruW4/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/8RuJ23GPbruW4/giphy.gif" alt="question gif from series" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can easily end up in a situation where your app specification is something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I want to be able to log in and like... upload and download stuff. Then users could register and can download stuff. But certain people could only download certain stuff!"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Normally&lt;/strong&gt; you wouldn't get a &lt;em&gt;"specification"&lt;/em&gt; like this at a &lt;em&gt;web development studio&lt;/em&gt;. You would get &lt;strong&gt;interface design&lt;/strong&gt; sheets, &lt;strong&gt;database schema specs&lt;/strong&gt;, maybe even a complete &lt;strong&gt;design theme&lt;/strong&gt;.&lt;br&gt;
You're not that lucky this time. Now what.&lt;/p&gt;

&lt;p&gt;Well, you cannot teach product development to your client, especially if you're also inexperienced - but you can &lt;strong&gt;ask questions until a working solution unfolds&lt;/strong&gt;! Basically: Review, build, synchronize.&lt;/p&gt;

&lt;h3&gt;
  
  
  In steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Review&lt;/strong&gt; your client's feature requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Construct&lt;/strong&gt; technical solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Align&lt;/strong&gt; technical implementation details and constraints with client expectations. &lt;em&gt;Educate&lt;/em&gt; your client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust&lt;/strong&gt; your implementation to be in accord with your client's needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rinse and repeat.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Be thorough, I can’t stress this enough. It can be super annoying to redesign a whole database or API, just because you were not extensive enough in explaining limitations created by a certain implementation choice, at a certain point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be your own product manager
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnk3609fbemhe3uix4g0z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnk3609fbemhe3uix4g0z.gif" alt="council of characters" width="500" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At large software companies, you always have a &lt;em&gt;team lead&lt;/em&gt;, or some kind of manager, who serves as &lt;strong&gt;the first layer of defense&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Basically how it works:&lt;/em&gt;&lt;br&gt;
Other parts of your company may throw implementation ideas and random tasks at you, and your manager is the one who decides &lt;strong&gt;what tasks are accepted&lt;/strong&gt;, depending on your team's experience, scope, time restrictions, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a &lt;em&gt;freelancer&lt;/em&gt;, &lt;strong&gt;you'll have to step up and steer your client away from design ideas that would result in harmful technical decisions&lt;/strong&gt;.&lt;br&gt;
Communicating technical debt is not trivial, and there are &lt;a href="https://devops.com/communicating-with-management-about-technical-debt/"&gt;whole articles&lt;/a&gt; about it.&lt;/p&gt;

&lt;p&gt;The point is, we can do anything with code, but it doesn't mean that we should. As the developer, &lt;strong&gt;you should be the one who draws the line&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Careful &lt;strong&gt;source code management is also key&lt;/strong&gt;. You won't be able to adapt fluently if your git repo is a mess. It's pretty hard to revert features if your commits are not granular enough and you don't document well with proper commit messages and tags.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything has a price
&lt;/h3&gt;

&lt;p&gt;If you're alone, or you have little help &lt;em&gt;(like a couple of designers throwing concepts and UI mockups at you - which is not always help, let's be honest)&lt;/em&gt; you probably have to consider &lt;strong&gt;what you're capable to do alone given a specific amount of time and resources&lt;/strong&gt;. When your client wants something beyond your limits, the best is to &lt;strong&gt;expose these limitations and the price they might have to pay&lt;/strong&gt; (in time, or resources) &lt;strong&gt;to accomplish what they want, despite the boundaries.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;I hope you've enjoyed this read! Happy coding!&lt;br&gt;
&lt;a href="https://i.giphy.com/media/LQjqYNrXB0fDy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/LQjqYNrXB0fDy/giphy.gif" alt="farewell gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>career</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Hospitality should be automated. Here's why.</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Sat, 04 Jul 2020 19:54:55 +0000</pubDate>
      <link>https://dev.to/pencillr/hospitality-should-be-automated-here-s-why-31mp</link>
      <guid>https://dev.to/pencillr/hospitality-should-be-automated-here-s-why-31mp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Just a heads up: This is more of a blog post, noting technical. 🍹&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The better version
&lt;/h1&gt;

&lt;p&gt;This summer I visited a small historic town in the countryside with my fiance, and one afternoon we ended up at this awesome small restaurant. It was a Tuscany style place in the embrace of the local vineyards above the city, with a great view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyegcee257vkzt2rcco43.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyegcee257vkzt2rcco43.jpg" alt="vineyard restaurant" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've read me before, you might know that &lt;a href="https://dev.to/pencillr/i-m-an-ex-bartender-waiter-who-is-now-a-web-developer-and-devops-engineer-ask-me-anything-14gb"&gt;I've spent 6 years&lt;/a&gt; in international hospitality somewhere between uni and my tech career. As a result, when it comes to restaurant service, &lt;strong&gt;I know what's going on&lt;/strong&gt;, and it's &lt;em&gt;pretty hard&lt;/em&gt; to amaze me. Now they've done it. It was a &lt;strong&gt;culinary revelation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let me just quote some parts of my Tripadvisor review:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Then this guy who owns the place comes forward to have one or two good words with you. You don't have the world's largest menu, but you have top-quality fish, beef, pork prepared with the mastery of an Italian grandmother. I've seen some people complain about longer service times. Bro. I've seen how 5-star hotel sous-chefs work on the food "production line" to get your "fast service"...&lt;br&gt;
...Then you get &lt;em&gt;LOCAL&lt;/em&gt; wines with your food. And I don't mean local like &lt;em&gt;"wine from the city that you can buy in Tesco's"&lt;/em&gt; kind of local. I mean &lt;em&gt;"from the local cellars that you can't get anywhere"&lt;/em&gt; local.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now I must let you in on a secret. It was not the steak, wines, or the view that won my admiration. It was &lt;strong&gt;the sincerity.&lt;/strong&gt; The candor of the service.&lt;/p&gt;




&lt;h2&gt;
  
  
  Here’s something you probably don’t know about restaurant people.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;They're usually fed up with you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm exaggerating a bit, but a lot of times all the charm that you experience is just &lt;em&gt;part of the facade&lt;/em&gt;. There is a particular &lt;em&gt;method&lt;/em&gt; to this deceit - it is how hospitality businesses intrinsically work. It's all very simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The business owner is looking for the best possible &lt;strong&gt;optimization&lt;/strong&gt; between &lt;strong&gt;necessary resource costs&lt;/strong&gt; and the resulting &lt;strong&gt;income potential&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Turns out when you're a hotel or restaurant owner, you &lt;em&gt;don't have much space to optimize&lt;/em&gt;. You need good ingredients, competent staff, good equipment. There is still one thing though. As always, &lt;strong&gt;it's the human&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The easiest, safest solution is to optimize on the workforce.&lt;/strong&gt; A little fewer waiters, a single bartender, and a couple of chefs working overtime can run the business!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Well, they will die of exhaustion on the floor, while trying to wear their smiley face, but that's not all!&lt;br&gt;
They will even provide their &lt;strong&gt;creativity, humor, and charm&lt;/strong&gt; to help the owner &lt;strong&gt;get away with logistic mistakes and bad business decisions&lt;/strong&gt; when ingredients, or tools are missing.&lt;br&gt;
Or when people are waiting &lt;strong&gt;ten minutes for a jug of water&lt;/strong&gt; because the boss put only &lt;strong&gt;two guys&lt;/strong&gt; for the fully booked night shift.&lt;/p&gt;

&lt;p&gt;Consequently, even &lt;em&gt;hotel bistros&lt;/em&gt; end up like &lt;em&gt;franchise restaurants&lt;/em&gt;, exploiting their workers, while trying to squeeze out as much profit as possible. When I walk into one all I see is a &lt;strong&gt;capitalist purgatory&lt;/strong&gt;, despite all the amenities. But that's probably just my distorted vision, due to my past experiences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1d4710226xl6peomqhlz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1d4710226xl6peomqhlz.jpg" alt="Old building side" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Now, this is why I really appreciated that small hillside restaurant.
&lt;/h2&gt;

&lt;p&gt;The service was not blazing fast, the food was not always the same, and the wines were different from season to season. Instead, it was &lt;strong&gt;real&lt;/strong&gt; and &lt;strong&gt;humble&lt;/strong&gt; hospitality. They did it because they loved doing it.&lt;br&gt;
These places will never be out of fashion - &lt;strong&gt;but let the rest be done by bots!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Obviously, this is not something that happens overnight.
&lt;/h3&gt;

&lt;p&gt;I see that hotels and restaurants employ a tremendous amount of people, and many of them might like their jobs. Though it's a volatile industry - and not even robust, as COVID19 has shown us. I believe in time these jobs can slowly fade and less demanding ones can replace them, as it happened many times in the past. I'm also sure that hospitality done by people will always be something that the rich will indulge themselves in.&lt;/p&gt;

&lt;p&gt;I just hope the future will be more righteous in this regard.&lt;/p&gt;

</description>
      <category>writing</category>
    </item>
    <item>
      <title>Survival package (not just) for devOps newbies</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Thu, 02 Jul 2020 18:39:48 +0000</pubDate>
      <link>https://dev.to/pencillr/survival-package-not-just-for-devops-newbies-59pe</link>
      <guid>https://dev.to/pencillr/survival-package-not-just-for-devops-newbies-59pe</guid>
      <description>&lt;h1&gt;
  
  
  Welcome to your company!
&lt;/h1&gt;

&lt;p&gt;Landing at a big software corporation can be tough, especially if their onboarding process is outdated - &lt;em&gt;which often is!&lt;/em&gt;- along with their unmaintained wiki pages and workflow documentations. Discovering domain secrets is an exhaustive task by itself. The least you need is troubles with general things like coding and communication.&lt;/p&gt;

&lt;p&gt;I'm going to share some &lt;strong&gt;tools&lt;/strong&gt; that I regularly throw at newcomers at my place. I hope it can help others as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://sourcemaking.com/design_patterns"&gt;Design Patterns&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Not strictly DevOps related, but it can come in handy, especially if you're a &lt;strong&gt;Bootcamp developer&lt;/strong&gt; and you didn't have a lot of software design classes. &lt;em&gt;SourceMaking&lt;/em&gt; is awesome, make sure to check out their articles about antipatterns as well!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://linuxjourney.com/"&gt;Linux Basics&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A good grasp on Linux systems is key at any software job these days. &lt;em&gt;Linuxjourney&lt;/em&gt; is a beautifully designed informative site that helps you understand all the basic concepts.&lt;br&gt;
For detailed command-line help, I suggest &lt;a href="https://github.com/jlevy/the-art-of-command-line"&gt;the-art-of-command-line&lt;/a&gt; by &lt;a href="https://github.com/jlevy"&gt;Joshua Levy&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/dylanaraps/pure-bash-bible"&gt;Bash Scripting&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Bash is an awesome language. It's super powerful and super permissive - consequently &lt;strong&gt;super dangerous&lt;/strong&gt; if you're not sure how to do things in a safe way. Knowing good boilerplate is essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://yourbias.is/"&gt;Art of biases&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Making decisions about software can be difficult, but I've learned that knowing the most common biases can protect us from harmful patterns, general management mistakes, sometimes even from technical debt. That's why this site is awesome. Careful with &lt;a href="https://yourbias.is/the-sunk-cost-fallacy"&gt;this one&lt;/a&gt; for example. This deserves a whole article.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.hofstede-insights.com/product/compare-countries/"&gt;International communication&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You might end up being puzzled by the behavior of your colleagues if you've never been exposed to their culture. This tool of &lt;em&gt;hofstede-insights&lt;/em&gt; can come quite handy to decipher some differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just some &lt;a href="https://less.works/"&gt;&lt;em&gt;Less&lt;/em&gt; infographics&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Large scale scrum is &lt;em&gt;the way&lt;/em&gt; these days. I had to include it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How others do it
&lt;/h2&gt;

&lt;p&gt;It can be really useful to look at other companies' blogs and see how they do stuff. For example, I really enjoy &lt;a href="https://technology.riotgames.com/news/putting-jenkins-docker-container"&gt;Riot's tech blogs&lt;/a&gt;, check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  One for the fun
&lt;/h2&gt;

&lt;p&gt;Which is your company? Elaborate in the comments!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XP7CpUFH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/FH1arHq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XP7CpUFH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/FH1arHq.jpg" alt="infographic" width="600" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>career</category>
      <category>motivation</category>
    </item>
    <item>
      <title>18 Common Concepts in Developer Jargon for Muggles</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Fri, 24 Apr 2020 18:44:00 +0000</pubDate>
      <link>https://dev.to/pencillr/18-common-concepts-in-developer-jargon-for-muggles-2gl</link>
      <guid>https://dev.to/pencillr/18-common-concepts-in-developer-jargon-for-muggles-2gl</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is about my past experiences with tech jargon, during the first two years of my software dev career. I highly recommend it to newbies, especially for Bootcamp devs who are just hopping into the industry.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  'It's some kind of elvish...'
&lt;/h2&gt;

&lt;p&gt;I came into software development from a bar counter. Well, I've spent some time being a physics undergrad, so I had a basic idea about cognitively intensive work but still, tech jargon really caught me cold.&lt;/p&gt;

&lt;p&gt;I was not totally a &lt;em&gt;muggle&lt;/em&gt;, had some programming classes in uni, but that's nothing compared to the experience of people who &lt;em&gt;discuss software related technical problems every day.&lt;/em&gt; Not even mentioning that they do this in the context of specific, &lt;em&gt;work-related domains&lt;/em&gt;. Coming into this as a junior can be pretty intimidating.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyf0j4pe1ejcq82rsp5ko.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyf0j4pe1ejcq82rsp5ko.jpg" alt="Allen from Hangover math problem meme" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, tech companies are usually promoting learning, as it's an essential part of almost every developer's job, thus they support &lt;strong&gt;bold proactivity and making mistakes&lt;/strong&gt; during work rather than punishing it.&lt;/p&gt;

&lt;p&gt;The bar might be high to get into some well-paying job, but usually, after you've hit that bar, you can indulge in blessed ignorance for a few weeks &lt;em&gt;-sometimes even months-&lt;/em&gt; until you catch up with your colleagues in domain knowledge and local practices/tools. &lt;/p&gt;

&lt;p&gt;And you'll need this time for sure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runes and Incantations
&lt;/h2&gt;

&lt;p&gt;The first thing that I realized as a junior, was that how effortlessly my colleagues can express relationships and issues in a technical topic, using the perfect vocabulary. You know it's much harder to explain &lt;strong&gt;"you know there is this string handler operation that finds the domain in the text, that you keep copying around here and there"&lt;/strong&gt; rather than saying &lt;strong&gt;"there's a redundant URL parser in your code, extract it"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my first days, I've created an &lt;em&gt;'expressions'&lt;/em&gt; note in &lt;a href="https://keep.google.com/"&gt;Google Keep&lt;/a&gt; to keep track of all the unknown concepts that I heard flying around me so I could google them later. I still have the note, and I'm still using it! Now I've decided to share it so others could benefit from it. These are not just technical expressions, but also general stuff that people tend to throw around in tech.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8gmk3ifi9uoq7dkmyc9g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8gmk3ifi9uoq7dkmyc9g.jpg" alt="Harry potter meme" width="621" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heads up number one: non-native English speaker here&lt;/strong&gt;&lt;br&gt;
Some of these might not be a big deal if you're native English. Funny thing is: I'm not native English but all these expressions are written English in my notes too - which means these are words that we use in English even when we're talking between Hungarian developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heads up number two: gonna keep it casual&lt;/strong&gt;&lt;br&gt;
I'm not going to write down huge mathematical definitions, so this is gonna be pretty casual. I'm gonna go with an &lt;strong&gt;'explain like I'm five'&lt;/strong&gt; approach. Expect &lt;em&gt;'stuffs'&lt;/em&gt; and &lt;em&gt;'thingies'&lt;/em&gt;. I'm also not going into structural design patterns, like Proxy, Decorator, Adapter, Bridge, etc. For those, you'll gonna have to do a Design Patterns course if you don't know them yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here we go!&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Nested
&lt;/h3&gt;

&lt;p&gt;I thought we could start with a very simple one. I bet this is nothing new, it was just not intuitive for me to use it in a tech context at first. I think it first came up with JSON. We refer to embedded structures as nested ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"streetAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"21 2nd Street"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New York"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postalCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10021-3100"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It kind of feels stupid to google &lt;em&gt;'access JSON in JSON'&lt;/em&gt; rather than googling &lt;em&gt;'access nested JSON objects'&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Best Effort
&lt;/h3&gt;

&lt;p&gt;It's not super techy, but as a non-native English person, I did not encounter this expression before my tech jobs. Things that we do as &lt;em&gt;'Best effort'&lt;/em&gt; is something that &lt;em&gt;"we do if the circumstances allow it"&lt;/em&gt;, almost like a &lt;em&gt;"maybe if it's possible, but not necessarily"&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Race Condition
&lt;/h3&gt;

&lt;p&gt;I thought the official Wikipedia explanation is not too heavyweight here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Race condition is a condition of a system where the system's substantive behavior is dependent on the sequence or timing of other uncontrollable events.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In practice, developers tend to carelessly throw around &lt;code&gt;'race condition'&lt;/code&gt; anytime when &lt;em&gt;some process is hitting some other process&lt;/em&gt; in the software, resulting in some unwanted behavior (even if it doesn't always refer to that). A good example is when two or more threads can access shared data and they try to change it at the same time, resulting in some unexpected havoc.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Literals
&lt;/h3&gt;

&lt;p&gt;A tricky one. In programming, a literal is basically a value that you write to express something &lt;em&gt;literally&lt;/em&gt;. With a javascript example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;const&lt;/code&gt; is a keyword, &lt;code&gt;a&lt;/code&gt; is the variable name, and &lt;code&gt;30&lt;/code&gt; is a &lt;strong&gt;literal&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Idempotent
&lt;/h3&gt;

&lt;p&gt;A command or function is idempotent when running it several times produces the same result as running it only once. &lt;br&gt;
A good example is the &lt;code&gt;touch&lt;/code&gt; command in bash. Creating a file with touch, and then creating a file with the same name as before will not yield a new file on the second run.&lt;br&gt;
But then again, &lt;code&gt;rm&lt;/code&gt; is not idempotent, as deleting a file twice will throw an error - as the file is deleted on the first run, and it does not exist on the second run.&lt;/p&gt;

&lt;p&gt;Another example is a constructor of a &lt;a href="https://link.springer.com/chapter/10.1007%2F978-1-4302-2370-2_23"&gt;singleton&lt;/a&gt;. Running it when the singleton instance was already created does not result in a new instance - just yields the already existing one.&lt;/p&gt;


&lt;h3&gt;
  
  
  6. Agnostic
&lt;/h3&gt;

&lt;p&gt;This expression is similar to saying something has &lt;em&gt;interoperability&lt;/em&gt;. We're using it to describe a high degree of &lt;em&gt;compatibility&lt;/em&gt;. So, something is system-agnostic if it functions without knowing the underlying details of a system that it is working within.&lt;/p&gt;

&lt;p&gt;Or for example: if a device supports both USB and FireWire, and doesn't care which of these interfaces the data arrived on, it's agnostic, or data agnostic.&lt;/p&gt;


&lt;h3&gt;
  
  
  7. Redundant
&lt;/h3&gt;

&lt;p&gt;Redundancy is a very common theme in software development and it's a tricky one, as it can be used in a positive and negative sense as well.&lt;/p&gt;

&lt;p&gt;Usually, when a developer says that some code is &lt;em&gt;redundant&lt;/em&gt;, she/he essentially means that &lt;strong&gt;some parts of a program are unnecessary or unnecessarily recurring&lt;/strong&gt;.&lt;br&gt;
Dead code, unused variables, repeatedly recomputed values can all be redundancy issues. The typical case is when there is a certain operation in functions which is common, thus could be extracted to a separate step to reduce code replication. In this case, redundancy is the result of lazy programming and is generally considered bad practice...&lt;/p&gt;

&lt;p&gt;...yet on the other hand, when we're talking about security for example, suddenly there's no redundancy that could be enough! &lt;em&gt;(I'm exaggerating of course.)&lt;/em&gt; For example, a repeatedly recomputed value, or a repeated cache validation at the right places can be a great improvement when trying to ensure security. In this case, redundancy is about data validation and is generally considered good practice.&lt;/p&gt;


&lt;h3&gt;
  
  
  8. Transitive
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Transitive_relation"&gt;math definition&lt;/a&gt; is really straightforward, but with a mundane example:&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;there's a nice gastro show in the TV during Saturday morning&lt;/code&gt; that &lt;code&gt;gets my aunt Theresa in the mood to cook&lt;/code&gt; and that results in &lt;code&gt;me eating a cranberry pie during the afternoon&lt;/code&gt;, then me having an afternoon treat is transitively related to having a nice cooking show on schedule during the morning.&lt;/p&gt;

&lt;p&gt;For me, this expression came up when we were looking at python libraries during work and I had to realize that some python libraries actually have other python libraries as their dependencies - and that makes your code transitively depend on the dependencies of your libs. Wow.&lt;/p&gt;


&lt;h3&gt;
  
  
  9. Semantics
&lt;/h3&gt;

&lt;p&gt;Okay, this is just a fancy word regarding the 'meaning of a language', or in our case the meaning of syntactically valid strings defined by a specific programming language.&lt;/p&gt;

&lt;p&gt;When I say &lt;em&gt;'python is semantically simpler than Java'&lt;/em&gt; I mean that in python many things &lt;strong&gt;can be expressed simpler and shorter than in Java&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  10-11. Explicit / Implicit
&lt;/h3&gt;

&lt;p&gt;Two very important expressions, often used in programming. &lt;strong&gt;Implicit&lt;/strong&gt; is often used to refer to &lt;strong&gt;something that’s done for you by other code behind the scenes&lt;/strong&gt;. Consider this &lt;a href="https://groovy-lang.org/"&gt;&lt;code&gt;groovy&lt;/code&gt;&lt;/a&gt; expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Richie'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I'm hoping that my expression will be handled as a string because &lt;em&gt;&lt;code&gt;groovy&lt;/code&gt; implicitly knows that this literal refers to a string&lt;/em&gt;, not a number or an array for instance.&lt;br&gt;
But the nice thing is that in &lt;code&gt;groovy&lt;/code&gt; I can say this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&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="s1"&gt;'Richie'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I &lt;em&gt;explicitly describe that the literal is a type of String&lt;/em&gt; that I'm storing to the &lt;code&gt;name&lt;/code&gt; variable.&lt;/p&gt;




&lt;h3&gt;
  
  
  12. Interpolation
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;(Parameter Expansion, Parameter Substitution)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;String interpolation is the process of &lt;em&gt;evaluating a string literal containing one or more placeholders, thus yielding a result in which the placeholders are replaced with their corresponding values&lt;/em&gt;.&lt;br&gt;
You know: &lt;strong&gt;Putting the strings into other strings!&lt;/strong&gt; See the following javascript example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;condiment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pepper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// interpolation happens here:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Can I have some fresh &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;condiment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; on my steak?`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  13. Robustness
&lt;/h3&gt;

&lt;p&gt;This is a term often thrown around in &lt;em&gt;DevOps&lt;/em&gt;. Robustness is &lt;strong&gt;the ability of a computer system to cope with errors during execution&lt;/strong&gt;. Basically telling how error resistant is something.&lt;/p&gt;




&lt;h3&gt;
  
  
  14. Benchmark
&lt;/h3&gt;

&lt;p&gt;A benchmark is a certain standard or point of reference against which things may be compared. Basically, a benchmark is an abstract point that we use to express some quality of a system.&lt;br&gt;
Like if my system reached the 3 beer benchmark during a Friday night I'm much more susceptible to end up in a club.&lt;/p&gt;




&lt;h3&gt;
  
  
  15-16. Declarative / Imperative
&lt;/h3&gt;

&lt;p&gt;A very simple one which can be a bit hard to understand. We like to call programming languages, tools, or design methods imperative/declarative.&lt;/p&gt;

&lt;p&gt;I'll start with the ancient sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“You know, imperative programming is like how you do something, and declarative programming is more like what you do, or something."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Better, let's do a mundane example! Let's say you have a &lt;strong&gt;puzzle completing machine&lt;/strong&gt; that you want to complete a hard puzzle with: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An imperative way to complete the puzzle is to &lt;em&gt;describe to the machine step by step&lt;/em&gt; &lt;strong&gt;HOW&lt;/strong&gt; to pick up the pieces, and what-and-when to do with them.&lt;/li&gt;
&lt;li&gt;A declarative way to complete the puzzle is to tell the machine &lt;strong&gt;WHAT&lt;/strong&gt; &lt;em&gt;the end result should be&lt;/em&gt; and let the machine figure out how to get the job done using its built-in mechanics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React is declarative. Or if you're DevOps, Bazel build language is for example declarative.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In React you're not explaining programmatically how to change the DOM, you're just managing the state changes, and React takes care of the DOM updates for you.&lt;/li&gt;
&lt;li&gt;In the Bazel BUILD files, you declare rules in a build graph. You're describing dependencies, but the build steps are run behind the scene for you (though you have some access to the inner implementation, configuration, etc).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  17. Dependency Injection
&lt;/h3&gt;

&lt;p&gt;I think this one is one of the hardest to grasp. Dependency injection is a clean coding technique tightly connected to the SOLID coding principles, code testability, and Object-Oriented Programming. Actually it mostly comes up when using classes - and it's a question of how a class/object has access to some resources.&lt;/p&gt;

&lt;p&gt;Right now I'm going to give you my way of looking at it:&lt;br&gt;
Let's say you have a piece of logic (let it be a module, function, class, etc). Then let's just say you have another piece of logic as well (let's say it's a service or another function). The dependency injection is when you're providing the reference of the second piece of logic to the first one as a parameter, instead of having the reference right in the first piece.&lt;/p&gt;

&lt;p&gt;We like dependency injection because what you essentially do is you decouple the creation and management of a resource from your parent object.&lt;br&gt;
I really recommend this &lt;a href="https://stackoverflow.com/questions/130794/what-is-dependency-injection"&gt;StackOverflow&lt;/a&gt; post for references.&lt;/p&gt;




&lt;h3&gt;
  
  
  18. Lazy Initialization
&lt;/h3&gt;

&lt;p&gt;And we end with a simple one: In programming lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed.&lt;/p&gt;




&lt;p&gt;Hope you've enjoyed this small read!&lt;/p&gt;

</description>
      <category>career</category>
      <category>beginners</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>My full stack setup with React</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Thu, 26 Mar 2020 14:25:20 +0000</pubDate>
      <link>https://dev.to/pencillr/my-full-stack-setup-with-react-3pd1</link>
      <guid>https://dev.to/pencillr/my-full-stack-setup-with-react-3pd1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; In this post, I'll share my React-Express starter app, with some additional details and thoughts. Enjoy!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The &lt;em&gt;stack-nado&lt;/em&gt; age we're in 🌪
&lt;/h2&gt;

&lt;p&gt;Currently, we're living in times when it can be pretty hard to decide what technology is the best for our application. Although this confusion is actually just a &lt;em&gt;facade&lt;/em&gt; - we're perplexed by the many &lt;em&gt;colors of screwdrivers&lt;/em&gt; that we can pick up.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, clearly, technologies have their &lt;strong&gt;areas of expertise&lt;/strong&gt;, as they're all born to solve a specific problem. But the thing is, we humans are quite good at the &lt;em&gt;abstraction&lt;/em&gt; of problems - which results in us identifying similar root problems. This is how tools like Angular and React end up solving the same issue - modularized frontend. Also, this is why developers tend to say, that more often than not, your stack is just preference, rather than technical necessity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking a screwdriver
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F72cnjjpxf41pesy98let.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F72cnjjpxf41pesy98let.jpg" alt="Angular vs React meme" width="500" height="756"&gt;&lt;/a&gt;&lt;br&gt;
What I can tell you, however, is how I do/did these choices. I believe I'm a very versatile coder - one might say &lt;em&gt;"Jack of all trades, master of none"&lt;/em&gt;. What this means is that I'm not afraid to touch any part of the development process let it be frontend design or build optimization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;C'mon, I came to web development from corporate DevOps engineering.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When it was time to choose a js framework/library, I chose to work with React because it was the &lt;em&gt;most popular&lt;/em&gt; at that time. What this meant to me, was that &lt;strong&gt;it will be easier to find answers for it on StackOverflow&lt;/strong&gt;. I'm a simple guy.&lt;/p&gt;

&lt;p&gt;So this throws out &lt;a href="https://en.wikipedia.org/wiki/MEAN_(solution_stack)"&gt;MEAN&lt;/a&gt; stack. I was also insisting on using the least possible languages, so to stay in the javascript world &lt;a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)"&gt;LAMP&lt;/a&gt; was out of the picture too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server or serverless
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw66hpacq1mxesxzg46vx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw66hpacq1mxesxzg46vx.jpg" alt="Morpheus meme" width="642" height="389"&gt;&lt;/a&gt;&lt;br&gt;
The next choice is different, as it's more about features than preferences. I love &lt;a href="https://jamstack.org/"&gt;JAM&lt;/a&gt; stack solutions, for the ease of deployment and cost-effectiveness that they provide. When it comes to implementation, I prefer to use &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt; and just let Contentful/Wordpress and Netlify handle the backend. &lt;br&gt;
There are those times however when you want something more than just displaying static instances of some data models.&lt;br&gt;
&lt;em&gt;But still!&lt;/em&gt;&lt;br&gt;
Even when I need to create fully dynamic applications with database and login I prefer to use some lightweight solutions - like handling all these things from google &lt;a href="https://firebase.google.com/"&gt;Firebase&lt;/a&gt; and just stay on JAM stack land.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fullstack land
&lt;/h2&gt;

&lt;p&gt;Anyhow, sometimes &lt;strong&gt;you just can't live without your own API&lt;/strong&gt;. A lot of times my clients choose to have custom solutions. They don't want to pay to a CMS, or they want to avoid Firebase vendor lock-in, and just prefer to run everything on AWS EC2. Another example when you need to set up some service to support another application. &lt;/p&gt;

&lt;p&gt;These are the times when I go for &lt;a href="https://www.educative.io/edpresso/what-is-mern-stack"&gt;MERN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Or in my case PERN, as I prefer PostgreSQL over MongoDB. Unfortunately, it can be tedious work to set up all the dependencies and environment for this kind of app (or to undress some developed app just for the setup), hence came the idea to create some template.&lt;/p&gt;

&lt;p&gt;So, I've created this &lt;strong&gt;super simple application base&lt;/strong&gt; that can serve as a starting point for these full-stack apps. I've set it up in a way to support all my preferences, like CSS preprocessing, my linter setup, and so on. I'm sharing it hoping that it can help others too when starting a new project having a similar stack setup in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give us that starter app finally...
&lt;/h3&gt;

&lt;p&gt;Source code is accessible &lt;strong&gt;&lt;a href="https://github.com/rlenkov/fullstack-starter"&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
The app is a &lt;em&gt;starter&lt;/em&gt; - hence &lt;strong&gt;it's super simple&lt;/strong&gt;. There is a &lt;strong&gt;&lt;a href="https://pencillr-demo-app.herokuapp.com/"&gt;demo&lt;/a&gt;&lt;/strong&gt; of it on Heroku. It's basically just a React frontend that can send two kinds of requests to its server and handle the responses.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has a Node &lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt; backend where there is an example to help creating sub routers when implementing various API functionality.&lt;/li&gt;
&lt;li&gt;The frontend is &lt;strong&gt;React&lt;/strong&gt; bundled with &lt;strong&gt;Webpack&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For styling I'm using &lt;a href="https://sass-lang.com/"&gt;Sass&lt;/a&gt; CSS preprocessor, to support modularization.&lt;/li&gt;
&lt;li&gt;Frontend requests are run with &lt;a href="https://www.npmjs.com/package/axios"&gt;Axios&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It also contains my preferred &lt;a href="https://prettier.io/"&gt;prettier&lt;/a&gt; and &lt;a href="https://eslint.org/"&gt;eslint&lt;/a&gt; setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you'll find it useful!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pbtcBoJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/ypvzafveynm5q1njmrs3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pbtcBoJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/ypvzafveynm5q1njmrs3.gif" alt="plusone" width="610" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>An ode to Cross-origin image downloads</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Fri, 20 Mar 2020 14:01:11 +0000</pubDate>
      <link>https://dev.to/pencillr/an-ode-to-cross-origin-image-downloads-26o2</link>
      <guid>https://dev.to/pencillr/an-ode-to-cross-origin-image-downloads-26o2</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;So I'm developing this app, and my client is like: "Can I have just a download button for the images pls?" And all hell broke loose.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Longer preface
&lt;/h2&gt;

&lt;p&gt;Not long ago I started working on a resource sharing application for a client of mine. They're a design studio, and they wanted to have an app where they can distribute their work/images/source files, etc to their clients. The idea was to have a system where you can create and manage artifacts, users, user groups, and you're able to set up arbitrary access rights between them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Basically what they needed was something that my designer colleague described as a &lt;strong&gt;"google drive on drugs"&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we made it. How? that's a different story.&lt;br&gt;
Anyway. One day my client was like, &lt;em&gt;"It's cool that we can look at the images and right-click download them, but can we have a download button as well?"&lt;/em&gt;. I was like &lt;em&gt;"sure should be fairly simple"&lt;/em&gt;. It was not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intricacies of the anchor tag
&lt;/h2&gt;

&lt;p&gt;The first solution I found was simply using an anchor tag.&lt;br&gt;
So the anchor tag has this &lt;code&gt;download&lt;/code&gt; attribute. Our illustrious helper &lt;em&gt;w3Schools&lt;/em&gt; describes it with a fairly simple example:&lt;/p&gt;

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

&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/images/myw3schoolsimage.jpg"&lt;/span&gt; &lt;span class="na"&gt;download=&lt;/span&gt;&lt;span class="s"&gt;"w3logo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;As simple as it could be&lt;/em&gt; - so I thought, and gave it a go. But my browser did not give a damn about it and just displayed the image in the same tab. What I did not calculate with was that &lt;strong&gt;my images and all artifacts were served from an AWS S3 bucket&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same origin policy problems
&lt;/h2&gt;

&lt;p&gt;Turns out that in most browsers to be compliant with the &lt;em&gt;same-origin policy&lt;/em&gt;, the &lt;code&gt;download&lt;/code&gt; attribute only works for &lt;strong&gt;same-origin URLs&lt;/strong&gt;. Hence, it cannot be used to download resources served from a different origin. This is well described in this &lt;a href="https://www.chromestatus.com/feature/4969697975992320" rel="noopener noreferrer"&gt;chrome feature update doc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway even if it's served from the same origin there can be problems, which need to be resolved using &lt;code&gt;Content-Disposition&lt;/code&gt; header. I'm not going to go into this but here's a &lt;a href="https://weblog.west-wind.com/posts/2007/may/21/downloading-a-file-with-a-save-as-dialog-in-aspnet" rel="noopener noreferrer"&gt;great article&lt;/a&gt; about the topic. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Shortly&lt;/em&gt;: To inform the client that the content of the resource is not meant to be displayed, the server must include an additional header in the response. The &lt;code&gt;Content-Disposition&lt;/code&gt; header is the right header for specifying this kind of information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Looking for Workarounds
&lt;/h2&gt;

&lt;p&gt;The first thing I started to look for is some kind of workaround. Cross-origin image usage is well described at the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image" rel="noopener noreferrer"&gt;corresponding Mozilla page&lt;/a&gt;, but I needed a download. The following StackOverflow &lt;a href="https://stackoverflow.com/questions/49474775/chrome-65-blocks-cross-origin-a-download-client-side-workaround-to-force-down?answertab=votes#tab-top" rel="noopener noreferrer"&gt;post&lt;/a&gt; looked like the best approach for me. The point is that &lt;code&gt;:blob&lt;/code&gt; and &lt;code&gt;:data&lt;/code&gt; are unaffected so we can use a workaround using these, then fetch and emulating the download click.&lt;/p&gt;

&lt;h2&gt;
  
  
  CORS Errors
&lt;/h2&gt;

&lt;p&gt;After this, a new problem came up thanks to the &lt;strong&gt;&lt;code&gt;Cross-Origin Resource Sharing&lt;/code&gt; policy&lt;/strong&gt;. You can read up on the whole thing &lt;a href="https://javascript.info/fetch-crossorigin" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Read it. Seriously it's great and funny. I'm just putting here one quote: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"JavaScript also did not have any special methods to perform network requests at that time. It was a toy language to decorate a web page."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All I needed was to set up CORS on the &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html" rel="noopener noreferrer"&gt;AWS side like this&lt;/a&gt; but you might also be able to use a trick with cors proxies like &lt;a href="https://cors-anywhere.herokuapp.com/" rel="noopener noreferrer"&gt;cors-anywhere&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope these links helped others who end up having similar issues.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fypvzafveynm5q1njmrs3.gif" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fypvzafveynm5q1njmrs3.gif" alt="plusone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Cover image base Designed by katemangostar / Freepik"&lt;/sup&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>html</category>
      <category>aws</category>
    </item>
    <item>
      <title>Finally updated my personal site</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Fri, 20 Mar 2020 09:43:12 +0000</pubDate>
      <link>https://dev.to/pencillr/finally-updated-my-personal-site-4041</link>
      <guid>https://dev.to/pencillr/finally-updated-my-personal-site-4041</guid>
      <description>&lt;p&gt;Last year I went full freelance &lt;em&gt;webdev&lt;/em&gt;, after some years of corporate employment. It was a very busy and creative period of my life full of learning, and I really wanted to update my old site with my newly obtained skillset. Unfortunately due to this whole &lt;em&gt;covid-19 situation&lt;/em&gt;, I really had to hurry to get this site done to be able to put it into use.&lt;br&gt;
So my point is, it's beta, I'm still refining it. &lt;/p&gt;

&lt;p&gt;Check it out &lt;a href="https://www.lenkovits-develops.com/"&gt;HERE&lt;/a&gt;&lt;br&gt;
For comparison here's the &lt;a href="https://loving-hawking-c6ac25.netlify.com/"&gt;old site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's a &lt;strong&gt;Gatsby&lt;/strong&gt; site, using &lt;strong&gt;Contentful&lt;/strong&gt; as CMS. I know it's a bit cheesy but I must admit, I took the idea for the vertical menu from Riot's &lt;a href="https://playvalorant.com/en-gb/"&gt;Valorant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have at it dev.to!&lt;/p&gt;

</description>
      <category>react</category>
      <category>gatsby</category>
      <category>career</category>
      <category>javascript</category>
    </item>
    <item>
      <title>From corporate DevOps to freelance full-stack</title>
      <dc:creator>Richard Lenkovits</dc:creator>
      <pubDate>Thu, 19 Dec 2019 11:05:25 +0000</pubDate>
      <link>https://dev.to/pencillr/from-corporate-devops-to-freelance-full-stack-3bnb</link>
      <guid>https://dev.to/pencillr/from-corporate-devops-to-freelance-full-stack-3bnb</guid>
      <description>&lt;p&gt;I left my corporate DevOps job, to become a fully freelance full-stack web developer - this is a quick post to share some thoughts on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not my first
&lt;/h2&gt;

&lt;p&gt;Till 2019 mid-October I was a DevOps engineer at a global networking and telecommunications company. Meanwhile, I was already working part-time as a hobby web developer, so naturally, I had been considering to go full-time web dev. The stage was set, I knew my client, I had a running project. Clearly, it was not a &lt;em&gt;leap of faith&lt;/em&gt;, but when I finally decided to change jobs in October, I was terrified. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You should know about me that I'm not shy to execute a rapid and wild career change. At one point I went programmer from bartender - &lt;em&gt;discussion here&lt;/em&gt;:&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/pencillr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--odHwU8n7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F26825%252Fc9d06288-b195-4eed-b820-d45fc943518d.jpg" alt="pencillr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/pencillr/i-m-an-ex-bartender-waiter-who-is-now-a-web-developer-and-devops-engineer-ask-me-anything-14gb" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;I'm an ex-bartender/waiter who is now a web developer and DevOps engineer, Ask Me Anything!&lt;/h2&gt;
      &lt;h3&gt;Richard Lenkovits ・ Aug 8 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#ama&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Still, this time was different. I must admit &lt;strong&gt;I admired the company for contributing to my career&lt;/strong&gt;, and I wasn't comfortable to leave them hanging. They accepted me three years ago as a &lt;em&gt;non-experienced university student&lt;/em&gt; for an internship. &lt;strong&gt;In one year they made me a full-time developer and taught me everything I now know about software.&lt;/strong&gt; It was an extremely fruitful period of my life, and I was immensely grateful for being able to learn programming, development workflow, tooling, and all about the industry. They helped me enter the world of software when I was just a &lt;em&gt;guy from the street&lt;/em&gt;, and I will never forget that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yeah. They made it &lt;em&gt;really hard to leave&lt;/em&gt;, I give them that...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  However, times change
&lt;/h2&gt;

&lt;p&gt;After my first two years, I felt a bit stuck. I admit I'm not an easy personality, I thrive in progress, but I can't stand stagnation. I'm healthy when I can operate at the edge of my capabilities, so that I always learn something with every step, always exploring. If you have ever ended up in corporate software, you know it's nothing like that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nCgu8beE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/uvform35l6z7fxlv73uc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nCgu8beE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/uvform35l6z7fxlv73uc.jpg" alt="boring work meme" width="564" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The what and why of industry software development and its weaknesses is a big topic. We can talk about it for endless hours, &lt;strong&gt;preferably at a bar counter, given enough beer and wine&lt;/strong&gt;. I'm not going to get lost in this, but I'll mention a couple of things that really made me consider going freelance in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agile Waterfall🌊
&lt;/h3&gt;

&lt;p&gt;A lot of times when some new trend comes up, companies rush and start implementing them in huge overcontrolled waterfall processes. &lt;strong&gt;It usually starts on the top, in the head of a selected group of architects.&lt;/strong&gt; They are like some privileged &lt;em&gt;mages&lt;/em&gt;, disconnected from the rest of the company, sitting in a position which was acquired through company politics, connections, and/or age. They usually know nothing about recent trends, and the last code they touched was &lt;a href="https://en.wikipedia.org/wiki/Fortran"&gt;Fortran&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/COBOL"&gt;Cobol&lt;/a&gt;. At the &lt;em&gt;High Tower&lt;/em&gt; these &lt;del&gt;ancients&lt;/del&gt; architects sit down and &lt;del&gt;summon&lt;/del&gt; figure out some &lt;del&gt;arcane&lt;/del&gt; over-architectured &lt;del&gt;tomes&lt;/del&gt; blueprints.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ru-_bbe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/x6hrgbcdl8hs4yxrzj2u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ru-_bbe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/x6hrgbcdl8hs4yxrzj2u.jpg" alt="laughing rich man meme" width="620" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These &lt;em&gt;blueprints&lt;/em&gt; are then passed down through &lt;em&gt;666 levels of management&lt;/em&gt; until all the visibility and project control is lost in the intertwined threads and yarns of corporate society.&lt;/p&gt;

&lt;p&gt;In the end, it arrives at the actual developers, and when someone shouts out that &lt;em&gt;'But that's not how an API works'&lt;/em&gt; it's already late. The abomination must be wrought into code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Corporate resources + &lt;a href="https://www.lesswrong.com/posts/tyMdPwd8x2RygcheE/sunk-cost-fallacy"&gt;Sunk Cost Fallacy&lt;/a&gt; 💸
&lt;/h3&gt;

&lt;p&gt;In the world of startups, you can seriously jeopardize your business if you launch or even start to create a product without extensively studying your targeted consumer group. If you neglect research you can easily end up with an unsellable product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KiKrWVVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/JhgITFs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KiKrWVVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/JhgITFs.jpg" alt="Leonardo Di Caprio throwing money meme" width="576" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this is not the case in a large company! There, if the management wants a tool to be used, trust me it &lt;strong&gt;WILL&lt;/strong&gt; be used.&lt;/p&gt;

&lt;p&gt;The situation is especially uncomfortable in the case of &lt;em&gt;inner source software&lt;/em&gt; - so code that we write for our colleagues. The &lt;strong&gt;corporate bureaucracy&lt;/strong&gt; that comes with the work usually generates an immeasurable amount of &lt;em&gt;technical debt&lt;/em&gt;, and developers must do all kinds of abominable workarounds to comply with unrealistic designs. In the end, the product must be launched and used, whether the targeted &lt;em&gt;users&lt;/em&gt; like it or not. And if those users are within the company that can create a very toxic atmosphere.&lt;/p&gt;

&lt;p&gt;You don't notice these things first, but slowly during the years they really drove me away from corporate software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then came Freelancer Life
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Being a one-man army
&lt;/h3&gt;

&lt;p&gt;After the summer my freelance career &lt;strong&gt;started simultaneously with two projects&lt;/strong&gt;. It was a frontend job at first but it &lt;em&gt;quickly escalated to be a full-stack one&lt;/em&gt; as the expectations of my client grew. I learned an immense amount of things in the last few months, and my life changed greatly. Suddenly I had to realize that it's much harder to justify something I wrote if &lt;strong&gt;there's no one to do code review for me&lt;/strong&gt;. The expression of &lt;strong&gt;Work-Life balance&lt;/strong&gt; also started to make sense suddenly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kp3VHJVR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/hmf4t5pwjctz2vx323ug.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kp3VHJVR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/hmf4t5pwjctz2vx323ug.jpg" alt="motivational image" width="563" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A freelancer friend of mine warned me several times that I must really pay attention to this or I can easily end up burnt out, or depressed. Indeed the risks and responsibilities that come with being a contractor are considerable sometimes. Not having fix hours can be great sometimes but you can quickly end up messing around during the day and then &lt;em&gt;doing overtime after midnight&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The internet is talking to me
&lt;/h3&gt;

&lt;p&gt;An important benefit now is that I feel as if all the articles and topics that come about on my google feed are for me. This is more because I became a full stack web developer after being a DevOps guy. Now all these blog posts about &lt;em&gt;javascript frameworks, web trends, new tools&lt;/em&gt; suddenly sound relevant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EG5628jU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/mn9ezm5oossftasat9p4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EG5628jU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/mn9ezm5oossftasat9p4.jpg" alt="javascript joke" width="500" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Actually nowadays if you read an article about containers, cloud and site reliability solutions &lt;em&gt;- so basically DevOps stuff -&lt;/em&gt; &lt;strong&gt;even these are worded for small businesses and web developers because this market is bursting&lt;/strong&gt;. As a result, picking up and integrating new tech can be hard at a large software company. Previously I always felt overwhelmed when I was working on some DevOps solution with some new tech tool. Reading the tutorials all the help I got was how to make the tool work for some &lt;em&gt;small web app&lt;/em&gt; when what I wanted was a setup for the management of many gigantic &lt;em&gt;native telco network applications&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's great fun to make web apps
&lt;/h3&gt;

&lt;p&gt;Making smaller web apps feel very similar to when I was just creating small tools for fun when I was just a hobby developer. Sometimes working alone can be hard, but I'm happy that I can be more creative and independent.&lt;/p&gt;

&lt;h4&gt;
  
  
  I hope you liked reading this! Have a great day!
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pbtcBoJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/ypvzafveynm5q1njmrs3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pbtcBoJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/ypvzafveynm5q1njmrs3.gif" alt="plusone" width="610" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>career</category>
      <category>motivation</category>
    </item>
  </channel>
</rss>
