<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/atom-style.xml"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Hauleth&#x27;s blog</title>
    <subtitle>Blog about BEAM, Rust, fantasy &amp; stuff</subtitle>
  <link href="https://hauleth.dev/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://hauleth.dev/" rel="related"/>
  <generator uri="https://www.getzola.org/">Zola</generator>
  <updated>2026-07-04T00:00:00+00:00</updated>
  <author>
    <name>Hauleth</name>
  </author>
  <id>https://hauleth.dev/atom.xml</id>
    <entry xml:lang="en">
      <title>The Lion, The Witch, and the audacity of recruiters</title>
      <published>2026-07-04T00:00:00+00:00</published>
      <updated>2026-07-04T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/the-lion-the-witch-and-the-aduacity-of-recruiter/" type="text/html"/>
      <id>https://hauleth.dev/post/the-lion-the-witch-and-the-aduacity-of-recruiter/</id><summary>Some stories of how recruitment processes went completely bonkers. Incompetence,
lies, and plain lack of any respect or common sense from recruiters that I
encountered.
</summary><content type="html">&lt;p&gt;I am searching for a job. If you&#x27;ve read my posts recently you may have noticed
&lt;a href=&quot;#for-hire&quot;&gt;my &quot;for hire&quot; block&lt;&#x2F;a&gt; (hopefully it will disappear soon).
During that search I noticed a lot of different behaviours from recruitment
teams. However, two of them pushed me to write this article because of how bad
they were.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;the-lion-the-witch-and-the-aduacity-of-recruiter&#x2F;cover.png&quot; alt=&quot;The Lion, The Witch, and the audacity of this Recruiter&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Company names and details are changed to avoid any legal troubles. I will
try to stay as close to my experiences, but some details may be blurry.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;story-1-hop-ns&quot;&gt;Story 1: Hop.NS&lt;a class=&quot;zola-anchor&quot; href=&quot;#story-1-hop-ns&quot; aria-label=&quot;Anchor link for: story-1-hop-ns&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;While I was checking some old colleagues of mine at &lt;del&gt;Microsoft managed
corporate echo chamber&lt;&#x2F;del&gt; LinkedIn, I noticed that one of my old colleagues works
there and they had open positions available. I know the company from the past, when
they had quite an &quot;interesting&quot; hiring process, where they ordered you to work for
a week on the take-home project (fortunately they paid for that time). I hoped
it changed a little since then, and it did - now they hire you for one week,
where you work on the project. But let&#x27;s not get ahead.&lt;&#x2F;p&gt;
&lt;p&gt;I pinged two friends that work there so they could pass my details to the HR to
speed up the process a little bit. They were quite happy to do so and after that
I had a scheduled call with their CTO. The position was described as &quot;Senior
Elixir Developer&quot;, which fit my area of expertise and interest perfectly. I
talked with the CTO, we discussed details of the process, the teams, the job as
an &lt;em&gt;Elixir&lt;&#x2F;em&gt; developer, and everything seemed perfect. They sent me papers to
sign for my trial contract for that one week, where, according to the CTO, I was
supposed to work on a task, &lt;em&gt;that would become my job if they hired me&lt;&#x2F;em&gt;.
The paperwork went through smoothly. I waited for that Monday to see what
interesting projects I might be working on for that one week. Monday came. At
09:00, I was ready, and the wild ride began.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;day-1&quot;&gt;Day 1&lt;a class=&quot;zola-anchor&quot; href=&quot;#day-1&quot; aria-label=&quot;Anchor link for: day-1&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I checked my email and saw some credentials to log in to my (temporary)
corporate email, standard stuff. I wanted to join their Slack workspace - uh oh,
it didn&#x27;t work. It said that I needed to contact the administrator. Okay, but I
didn&#x27;t have any way of contacting them. I tried a few times and when it didn&#x27;t
work, I sighed and went to LinkedIn to message my friend over there to make
someone give me access. It took a while, so after spending 2–3 of my 40
contracted hours just trying to access Slack, I finally got in. Now I needed
access to GitHub. After some more pleading and another two hours of waiting, I
was able to clone the repository. Cool. However, I still didn&#x27;t know what I
would be doing there, as the person who was my overseer was in South America, so
I had a call scheduled at 18:00 to get details of my assignment. Nice, a whole
20% of my time there would be spent watching paint dry. So while I was waiting I
was reviewing the Elixir codebase (remember, that job was described as &lt;em&gt;Elixir&lt;&#x2F;em&gt;
developer). The codebase wasn&#x27;t that bad. I opened a small PR with a few fixes.&lt;&#x2F;p&gt;
&lt;p&gt;On the evening of the first day there was a call with a person who was
responsible for my task for the trial week. I wanted to see what interesting
task awaited me. The task was clear - I was supposed to maintain their browser
extension, written in TypeScript, and extend it with new features and UI design.
I asked whether that was really what they wanted me to do, as I had a little
experience with that stuff. I did it to make them reflect on what they just
said, but the person on the other end of the conversation confirmed that it was
what I was supposed to do. They even told me, directly to my face, that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I do not need to worry, because all backend work should be already done.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Awesome… So you say that I do not need to worry, because the job that I want to
do is what is already done, and the job that I really do not want to do is what
I need to do…&lt;&#x2F;p&gt;
&lt;p&gt;The call ended, and I went to sleep, wondering what they were trying to achieve.
Because it feels that it was making me to go postal.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;day-2&quot;&gt;Day 2&lt;a class=&quot;zola-anchor&quot; href=&quot;#day-2&quot; aria-label=&quot;Anchor link for: day-2&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I tried to run and understand what the hell I was supposed to do and how it even
worked. For that I needed to install Google Chrome, which I prefer to avoid in
favour of Safari and Firefox. I spent a few hours trying to build that thing
locally and figure out how to run it, which required some additional ping-pong
with other people to obtain credentials and other bits of access.&lt;&#x2F;p&gt;
&lt;p&gt;In the meantime I talked with one of the people that vouched for me for this job.
The conversation went a little bit like this:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Me&lt;&#x2F;strong&gt;: Is it normal that for the trial week, you give a task that is
completely unrelated to the area of expertise of the candidate?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Friend&lt;&#x2F;strong&gt;: Normally it is done in a way that the candidate should be out of
their comfort zone. However, if a backend developer would receive purely
frontend work, then I would say that something went wrong.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Me&lt;&#x2F;strong&gt;: Guess what…&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I discussed the matter with them for a while, and they said that if they would
be in my position, then they would call it off right there. I decided to
continue just because of my respect to the two people that vouched for me there.&lt;&#x2F;p&gt;
&lt;p&gt;In the dedicated Slack channel for my recruitment process, I asked a simple
question:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If I am hired after this process, will I continue working on this project, or
will it be something else?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The answer wasn&#x27;t reassuring:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Not always.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Of course you will, but we will not say that straight to your face.&lt;&#x2F;p&gt;
&lt;p&gt;In the meantime I, yet again, needed to chase people responsible for my task to
provide me with the design templates. It took several more hours and I
finally managed to run the browser extension locally. After about 10-12 hours of
the 40 hours of my trial week.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;day-3&quot;&gt;Day 3&lt;a class=&quot;zola-anchor&quot; href=&quot;#day-3&quot; aria-label=&quot;Anchor link for: day-3&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I managed to see how to work on this thing and I had some basic understanding of
what was going on and what needed to be done. Though I still hadn&#x27;t acquired the
arcane knowledge about debugging browser extensions. Yay, small steps forward.&lt;&#x2F;p&gt;
&lt;p&gt;By noon of the third day, just in the middle of my trial week, I received a message
that they were extending the scope of the task to some additional things. That
was when I finally snapped and prepared the wall of text explaining how
ridiculous they were with this task. I explained that it was nowhere near what
they marketed to me, and that the job description didn&#x27;t contain anything about
TypeScript and browser extensions. I repeatedly pointed out that I was a
&quot;backend-and-ops&quot; kind of engineer. This project was draining every last
bit of my sanity. I wrote to them: &quot;I prefer to take a bath with a toaster
rather than work another minute on this&quot;. I told them that the task was a waste
of both my time, and that the only reason I hadn&#x27;t called it off immediately was
out of respect for my friends who had vouched for me. I also noted that I would
write a piece about the whole process on my blog. The CTO&#x27;s answer was that they
understood, they wanted to check if I was &quot;a good fit for their culture&quot; (of
hiring backend engineers and assigning them unrelated frontend work), and they
asked me to not publish it because &quot;they felt they hadn&#x27;t done anything wrong&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;It took some time, but as you, my dear readers, could have noticed, I do not
give a damn about what they want.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;They paid me for that agonising 20 hours of my &quot;work&quot; there. 3-4 weeks later their
CTO wrote to me a message over LinkedIn to ask if I was interested in their
position of Staff Software Engineer. I asked him whether they still used that
bait-and-switch tactic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;story-2-perhapsmaybe&quot;&gt;Story 2: PerhapsMaybe&lt;a class=&quot;zola-anchor&quot; href=&quot;#story-2-perhapsmaybe&quot; aria-label=&quot;Anchor link for: story-2-perhapsmaybe&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This one will be a shorter one. Again a company where I have some friends. I
noticed that they had a position open for Software Engineer with Elixir and I
applied. I pinged these friends whether they could bump my application. One of
them was able to put me right in front of their VP of Infrastructure, who
supposedly was hiring manager for this position, so I hoped that it would be
quite quick.&lt;&#x2F;p&gt;
&lt;p&gt;It was not.&lt;&#x2F;p&gt;
&lt;p&gt;I sent my details on 27 May 2026. First contact from their recruitment team was
11 June 2026, over two weeks later, and only when I stalked the VP on LinkedIn
and sent them an invitation. The recruiter contacted me to schedule a call with
the said VP about my previous experiences and some introductions. The call in
question went rather smoothly. That one-hour conversation made me even more
interested in the role. It sounded like something I&#x27;d really enjoy.&lt;&#x2F;p&gt;
&lt;p&gt;After that call, they contacted me to ask about my availability for technical
calls. The &quot;interesting&quot; part was that it was meant to last for 5½ hours. Quite
substantial, but what you won&#x27;t do for a job (I also quite like talking with
fellow engineers, so it wasn&#x27;t much of a problem).&lt;&#x2F;p&gt;
&lt;p&gt;The interview consisted of three parts:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A one-hour &quot;Systems Design&quot; - where I was tasked with designing some asynchronous
payment system with synchronous payment gateway. I think it went quite okay.&lt;&#x2F;li&gt;
&lt;li&gt;A one-hour &quot;Coding Interview&quot; - LeetCode-like tasks where I was tasked with writing
some &quot;algorithms&quot; (cross product and some chess-horse jumping across a
keypad). I made some mistakes there while analysing big-O complexity of second
task, but overall, I felt quite good with my solutions.&lt;&#x2F;li&gt;
&lt;li&gt;A one-hour &quot;Technical Deep Dive&quot; - where I was talking about some of my old
projects (in this case &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Ultravisor&#x2F;ultravisor&quot;&gt;Ultravisor&lt;&#x2F;a&gt;)
and the technical details of it. What I did there and how I had done it. I
felt good, but my gut told me, that the other side wasn&#x27;t impressed or was
expecting something else.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All of that happened during one day, but with breaks between calls (30 minutes
and 2 hours respectively).&lt;&#x2F;p&gt;
&lt;p&gt;After these calls I waited. One day passed. Then another. At the end of the second
day I asked the recruiter whether they had any updates. They had, but the answer
was not what I expected - they rejected me. Well, disappointing, but it happens.
Shame, as I really wanted to work with my friends over there, as I know that
they&#x27;re excellent engineers. The email contained one line though, that made me
facepalm:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Please note that due to the high volume of applicants, we do not share
individualized feedback.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Probably anyone that is looking for a job right now has seen that multiple
times already.&lt;&#x2F;p&gt;
&lt;p&gt;I would let it slip, if only they would not send me another email a week later.
The email read:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;From&lt;&#x2F;strong&gt;: PerhapsMaybe Hiring Team&lt;br &#x2F;&gt;
&lt;strong&gt;Subject&lt;&#x2F;strong&gt;: PerhapsMaybe Candidate Experience Survey&lt;&#x2F;p&gt;
&lt;p&gt;Hi Łukasz,&lt;&#x2F;p&gt;
&lt;p&gt;We want to ensure that our recruiting process is efficient and candidates have
a great experience. We&#x27;re sending you this survey to gather some honest
feedback about your recent interview.&lt;&#x2F;p&gt;
&lt;p&gt;Please take a moment to give us your feedback and tell us what you think could
be improved about your experience.&lt;&#x2F;p&gt;
&lt;p&gt;[link to survey]&lt;&#x2F;p&gt;
&lt;p&gt;Sincerely, The PerhapsMaybe Talent Team&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Despite having about 5 hours of recordings and probably some automated
notes from meetings (of course I was forbidden from using any AI for notes), are
you not willing to compose 3-4 sentences of why you do not want to hire me? But
I am supposed to provide you with details of how your process is going and how
you can reject more candidates faster? That requires some audacity.&lt;&#x2F;p&gt;
&lt;p&gt;My response to that was that, as I see it, I wasn&#x27;t a candidate, but rather a
contractor whose task was to assess their hiring process. So I asked the
recruiter for their billing details so I could invoice them at my contractor
rates.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-words&quot;&gt;Final Words&lt;a class=&quot;zola-anchor&quot; href=&quot;#final-words&quot; aria-label=&quot;Anchor link for: final-words&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The hiring market is fucked up. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;feed&#x2F;update&#x2F;urn:li:activity:7464732348287373312&#x2F;&quot;&gt;Recruiters will blame you for using LLMs in the
application process&lt;&#x2F;a&gt;. The applications often contain crap like:
&quot;why do you want to work for XYZ&quot; or &quot;what is the most exciting thing about
working for XYZ&quot;. It isn&#x27;t my job to sell your product to you. I want to do some
stuff that interests me and in return get money. There is no additional depth.
The only person in the world who can truly say they are excited about your
product is the company&#x27;s founder. At least until the IPO, as after that, the
shareholders do not give a damn either, all they want is to increase their
value.&lt;&#x2F;p&gt;
&lt;p&gt;Just to end with some light (unfortunately, I think that this light is at the
wrong end of the tunnel). There are some recruiters that I can say something
good about. When I was applying to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fresha.com&#x2F;&quot;&gt;Fresha&lt;&#x2F;a&gt; I was
speaking with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;christinekwong&#x2F;&quot;&gt;Christine Wong&lt;&#x2F;a&gt;.
She, after I was rejected due to &quot;not enough coding agents experience&quot;, asked me
to schedule a call to give me personalised feedback face to face. In that bleak
world we live, it was actually nice to see a real person showing respect for
candidates. And I am really grateful for that.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Guards! Guards!</title>
      <published>2026-06-27T00:00:00+00:00</published>
      <updated>2026-06-27T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/guards-guards/" type="text/html"/>
      <id>https://hauleth.dev/post/guards-guards/</id><summary>Small gotcha about boolean operators in Elixir.
</summary><content type="html">&lt;p&gt;Let&#x27;s start with simple quiz.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Given module defined as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; or&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_map_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_map_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; or&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Try to answer these questions.&lt;&#x2F;p&gt;
&lt;div class=&quot;question&quot; id=&quot;a-map&quot;&gt;
  &lt;p&gt;&lt;b&gt;Q:&lt;&#x2F;b&gt; What will be result of &lt;code&gt;Foo.a(%{foo: 21})&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;

  
  
  &lt;div class=&quot;option correct&quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;a-map&quot;
           id=&quot;a-map-a-1&quot;
           value=&quot;`true`&quot;
           &gt;
    &lt;label for=&quot;a-map-a-1&quot;&gt;&lt;code&gt;true&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  
  
  &lt;div class=&quot;option &quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;a-map&quot;
           id=&quot;a-map-a-2&quot;
           value=&quot;`false`&quot;
           &gt;
    &lt;label for=&quot;a-map-a-2&quot;&gt;&lt;code&gt;false&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  

  &lt;div class=&quot;answer&quot;&gt;
    &lt;div class=&quot;wrong&quot;&gt;WRONG&lt;&#x2F;div&gt;
    &lt;div class=&quot;right&quot;&gt;RIGHT&lt;&#x2F;div&gt;
    &lt;p&gt;This one is straightforward.&lt;&#x2F;p&gt;
&lt;p&gt;We check guard, it has one condition &lt;code&gt;is_integer(x) or is_map_key(x, :foo)&lt;&#x2F;code&gt;.
First one returns &lt;code&gt;false&lt;&#x2F;code&gt;, second returns &lt;code&gt;true&lt;&#x2F;code&gt;, Boolean&#x27;s alternative results
in &lt;code&gt;true&lt;&#x2F;code&gt; and first case is matched.&lt;&#x2F;p&gt;

  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;question&quot; id=&quot;a-int&quot;&gt;
  &lt;p&gt;&lt;b&gt;Q:&lt;&#x2F;b&gt; What will be result of &lt;code&gt;Foo.a(37)&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;

  
  
  &lt;div class=&quot;option correct&quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;a-int&quot;
           id=&quot;a-int-a-1&quot;
           value=&quot;`true`&quot;
           &gt;
    &lt;label for=&quot;a-int-a-1&quot;&gt;&lt;code&gt;true&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  
  
  &lt;div class=&quot;option &quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;a-int&quot;
           id=&quot;a-int-a-2&quot;
           value=&quot;`false`&quot;
           &gt;
    &lt;label for=&quot;a-int-a-2&quot;&gt;&lt;code&gt;false&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  

  &lt;div class=&quot;answer&quot;&gt;
    &lt;div class=&quot;wrong&quot;&gt;WRONG&lt;&#x2F;div&gt;
    &lt;div class=&quot;right&quot;&gt;RIGHT&lt;&#x2F;div&gt;
    &lt;p&gt;This one is straightforward as well.&lt;&#x2F;p&gt;
&lt;p&gt;We check guard, it has one condition &lt;code&gt;is_integer(x) or is_map_key(x, :foo)&lt;&#x2F;code&gt;.
First one returns &lt;code&gt;true&lt;&#x2F;code&gt;, second one isn&#x27;t fired at all, because &lt;code&gt;or&lt;&#x2F;code&gt; operator
is short circuiting.&lt;&#x2F;p&gt;

  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;question&quot; id=&quot;b-map&quot;&gt;
  &lt;p&gt;&lt;b&gt;Q:&lt;&#x2F;b&gt; What will be result of &lt;code&gt;Foo.b(%{foo: 21})&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;

  
  
  &lt;div class=&quot;option correct&quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;b-map&quot;
           id=&quot;b-map-a-1&quot;
           value=&quot;`true`&quot;
           &gt;
    &lt;label for=&quot;b-map-a-1&quot;&gt;&lt;code&gt;true&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  
  
  &lt;div class=&quot;option &quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;b-map&quot;
           id=&quot;b-map-a-2&quot;
           value=&quot;`false`&quot;
           &gt;
    &lt;label for=&quot;b-map-a-2&quot;&gt;&lt;code&gt;false&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  

  &lt;div class=&quot;answer&quot;&gt;
    &lt;div class=&quot;wrong&quot;&gt;WRONG&lt;&#x2F;div&gt;
    &lt;div class=&quot;right&quot;&gt;RIGHT&lt;&#x2F;div&gt;
    &lt;p&gt;Again, similar to the previous questions.&lt;&#x2F;p&gt;
&lt;p&gt;We check guard, it has one condition &lt;code&gt;is_map_key(x, :foo) or is_integer(x)&lt;&#x2F;code&gt;.
First one returns &lt;code&gt;true&lt;&#x2F;code&gt; and the rest is short circuited.&lt;&#x2F;p&gt;

  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;question&quot; id=&quot;b-int&quot;&gt;
  &lt;p&gt;&lt;b&gt;Q:&lt;&#x2F;b&gt; What will be result of &lt;code&gt;Foo.b(37)&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;

  
  
  &lt;div class=&quot;option &quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;b-int&quot;
           id=&quot;b-int-a-1&quot;
           value=&quot;`true`&quot;
           &gt;
    &lt;label for=&quot;b-int-a-1&quot;&gt;&lt;code&gt;true&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  
  
  &lt;div class=&quot;option correct&quot;&gt;
    &lt;input type=&quot;radio&quot;
           name=&quot;b-int&quot;
           id=&quot;b-int-a-2&quot;
           value=&quot;`false`&quot;
           &gt;
    &lt;label for=&quot;b-int-a-2&quot;&gt;&lt;code&gt;false&lt;&#x2F;code&gt;&lt;&#x2F;label&gt;
  &lt;&#x2F;div&gt;
  

  &lt;div class=&quot;answer&quot;&gt;
    &lt;div class=&quot;wrong&quot;&gt;WRONG&lt;&#x2F;div&gt;
    &lt;div class=&quot;right&quot;&gt;RIGHT&lt;&#x2F;div&gt;
    &lt;p&gt;Ouch, something changed…&lt;&#x2F;p&gt;
&lt;p&gt;Again, we check guard, one condition &lt;code&gt;is_map_key(x, :foo) or is_integer(x)&lt;&#x2F;code&gt;. We
hit the first clause &lt;code&gt;is_map_key(x, :foo)&lt;&#x2F;code&gt; but this &lt;strong&gt;doesn&#x27;t&lt;&#x2F;strong&gt; return &lt;code&gt;false&lt;&#x2F;code&gt;,
instead it fail. Failure in one of guard functions isn&#x27;t converted to &lt;code&gt;false&lt;&#x2F;code&gt;
but instead makes whole guard expression fail. This mean that &lt;code&gt;is_integer(x)&lt;&#x2F;code&gt;
part will &lt;strong&gt;never&lt;&#x2F;strong&gt; be called.&lt;&#x2F;p&gt;

  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;This behaviour is often surprising for a lot of Elixir developers, as it
seemingly breaks commutative property of boolean operators. However, to be
honest, these never were commutative because of short circuiting.&lt;&#x2F;p&gt;
&lt;p&gt;It seems that Elixir at the time of writing (Elixir 1.20.1, OTP 29) do not warn
about this issue.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Reviewing code requires reading</title>
      <published>2026-06-04T00:00:00+00:00</published>
      <updated>2026-06-04T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/review-requires-reading/" type="text/html"/>
      <id>https://hauleth.dev/post/review-requires-reading/</id><summary type="html"><p>On <a rel="external" href="https://lobste.rs">Lobste.rs</a> I have found today the article written by the Charity
Majors - CTO of the Honeycomb.io <a rel="external" href="https://charitydotwtf.substack.com/p/ai-enthusiasts-are-in-a-race-against">"AI enthusiasts are in a race against time, AI
sceptics are in a race against entropy"</a>. This was pretty good read until
there was this question posed:</p>
<blockquote>
<p>What would it take for you to feel comfortable shipping code to production
without reading it?</p>
</blockquote></summary><content type="html">&lt;p&gt;On &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&quot;&gt;Lobste.rs&lt;&#x2F;a&gt; I have found today the article written by the Charity
Majors - CTO of the Honeycomb.io &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;charitydotwtf.substack.com&#x2F;p&#x2F;ai-enthusiasts-are-in-a-race-against&quot;&gt;&quot;AI enthusiasts are in a race against time, AI
sceptics are in a race against entropy&quot;&lt;&#x2F;a&gt;. This was pretty good read until
there was this question posed:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;What would it take for you to feel comfortable shipping code to production
without reading it?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Her proposed solutions were:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Better evals? Better tests? Better feature flags, guardrails, observability?
Work on decoupling dependencies and reducing blast radius? Start with
something small and out of the critical path? What is the work we need to do
to prepare? What comes first, ordering-wise? Can we put that on the roadmap?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;But that is completely missing a point. The point of doing review is to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Diffusion_of_responsibility&quot;&gt;diffuse
responsibility&lt;&#x2F;a&gt;. No one want to be the sole person responsible for the
downtime of the system. No one want to be the sole person responsible for
security issues. No one want to be responsible for accidental data removal. And
the sole purpose of reviews is to remove that burden form single individual and
instead make it &lt;em&gt;team responsibility&lt;&#x2F;em&gt;. That way, the blame is &quot;spread&quot; among
writer and all reviewers.&lt;&#x2F;p&gt;
&lt;p&gt;If someone wants to remove that group responsibility and instead tell you to
&quot;approve without reading&quot; then why ask me to push the button manually at all? If
you want to pay someone for pushing a button without thinking then there you
are, here is a button for them to click:&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div&gt;
    &lt;center&gt;
        &lt;button id=&quot;pointless-button&quot; class=&quot;plausible-event-name=Review+Button+Merge&quot;&gt;Push me!&lt;&#x2F;button&gt;
    &lt;&#x2F;center&gt;
&lt;script&gt;
  const LYRICS = [
        &quot;Push me!&quot;,
        &quot;And then just touch me!&quot;,
        &quot;Till I can get my&quot;,
        &quot;Satisfaction&quot;
    ]
    let curr = 0
    document.addEventListener(&quot;DOMContentLoaded&quot;, () =&gt; {
        let button = document.getElementById(&quot;pointless-button&quot;)
        button.addEventListener(&quot;click&quot;, (ev) =&gt; {
            curr = (curr + 1) % LYRICS.length
            ev.target.innerText = LYRICS[curr]
        })
    })
&lt;&#x2F;script&gt;
&lt;noscript&gt;You probably have JavaScript disabled. Don&#x27;t worry, there is probably
  nothing interesting except some dumb jokes.&lt;&#x2F;noscript&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;&lt;small&gt;This is demo of my upcoming SaaS - button roulette, which will merge random PR
assigned to you that has all CI green. Perfect for &quot;AI enthusiastic&quot;
CTOs.&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Another reason why we do reviews is to &lt;em&gt;learn codebase&lt;&#x2F;em&gt;. In many projects the
codebase is too big to be constantly aware of all parts of the system. The
review is to force more people to have a look into different parts, to reduce
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bus_factor&quot;&gt;bus factor&lt;&#x2F;a&gt;, increase familiarity of the team with different parts, to teach
new team members about codebase and code culture.&lt;&#x2F;p&gt;
&lt;p&gt;If we force everyone to &quot;approve without reading&quot;, then we lose all that. That
way it not only increase the bus factor to 1, but also &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.independent.co.uk&#x2F;tech&#x2F;claude-down-not-working-anthropic-ai-b2987749.html&quot;&gt;externalise it to 3rd
party&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;So to answer Charity&#x27;s question:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;What would it take for you to feel comfortable shipping code to production
without reading it?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;My answer is:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Written waiver of responsibility in case of bugs, security issues, downtime,
etc. written by the person that issued such statement.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If I am forced to &quot;feel comfortable shipping unread code to production&quot;, then I
also want to feel secure from any consequences of such action. Simple as that,
but I highly doubt that I will get such waiver from anyone.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>How do I write Elixir tests?</title>
      <published>2026-05-13T00:00:00+00:00</published>
      <updated>2026-05-13T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/writing-tests/" type="text/html"/>
      <id>https://hauleth.dev/post/writing-tests/</id><summary>Personal guides for writing tests that are readable and maintainable. Stuff to
use, stuff to avoid, and how to organize stuff.

Furthermore, I think that mocking must be destroyed.
</summary><content type="html">&lt;p&gt;I created this post for myself to codify some basic guides that I use while
writing tests. If you, my dear reader, want to read this, then remember one
important thing:&lt;&#x2F;p&gt;
&lt;p&gt;These are &lt;strong&gt;guides&lt;&#x2F;strong&gt; not &lt;em&gt;rules&lt;&#x2F;em&gt;. Each codebase is different and exceptions are
expected and &lt;em&gt;will&lt;&#x2F;em&gt; happen. Just use the thing between your ears in your coding.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;subject-module-attribute-for-module-under-test&quot;&gt;&lt;code&gt;@subject&lt;&#x2F;code&gt; module attribute for module under test&lt;a class=&quot;zola-anchor&quot; href=&quot;#subject-module-attribute-for-module-under-test&quot; aria-label=&quot;Anchor link for: subject-module-attribute-for-module-under-test&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;While reading ExUnit test, I often find it hard to remember which of the used
modules is tested. Imagine test like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo should frobnicate when bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  bar &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pick_bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  assert &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyBehaviour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyImplementation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is not obvious at the first sight what is tested here. And this is pretty
simplified example. In real world it can became even harder to notice what is
module under test (MUT).&lt;&#x2F;p&gt;
&lt;p&gt;To resolve that I came up with a simple solution. I create module attribute
named &lt;code&gt;@subject&lt;&#x2F;code&gt; that points to the MUT:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyImplementation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo should frobnicate when bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  bar &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pick_bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  assert &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyBehaviour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now it is more obvious what is MUT and what is just wrapper code around it.&lt;&#x2F;p&gt;
&lt;p&gt;In the past I have been using &lt;code&gt;alias&lt;&#x2F;code&gt; with &lt;code&gt;:as&lt;&#x2F;code&gt; option, like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;alias&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyImplementation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Subject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, I find module attribute to be more visually distinctive, which make it
easier for me to notice &lt;code&gt;@subject&lt;&#x2F;code&gt; than &lt;code&gt;Subject&lt;&#x2F;code&gt;. But your mileage may vary.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;describe-with-function-name&quot;&gt;&lt;code&gt;describe&lt;&#x2F;code&gt; with function name&lt;a class=&quot;zola-anchor&quot; href=&quot;#describe-with-function-name&quot; aria-label=&quot;Anchor link for: describe-with-function-name&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;That one is pretty basic. I have seen that it is pretty standard for people:
when you are writing tests for module functions, then group them in &lt;code&gt;describe&lt;&#x2F;code&gt;
blocks that will contain name (and arity) of the function in the name. Example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Module under test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; y&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # some code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; FooTest&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; ExUnit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Case&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; async&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;  @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Foo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  describe &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;a&#x2F;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Some tests here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This allows me to see what functionality I am testing.&lt;&#x2F;p&gt;
&lt;p&gt;Of course that doesn&#x27;t apply to the Phoenix controllers, as there we do not test
functions, but tuples in form &lt;code&gt;{method, path}&lt;&#x2F;code&gt; which I then write as &lt;code&gt;METHOD path&lt;&#x2F;code&gt;, for example &lt;code&gt;POST &#x2F;users&lt;&#x2F;code&gt;. But the idea still stands - &lt;code&gt;describe&lt;&#x2F;code&gt; block
provide immediate context about what is tested.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;avoid-module-mocking&quot;&gt;Avoid module mocking&lt;a class=&quot;zola-anchor&quot; href=&quot;#avoid-module-mocking&quot; aria-label=&quot;Anchor link for: avoid-module-mocking&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In Elixir we have bunch of the mocking libraries out there, but most of them
have quite substantial issue for me - these prevent me from using &lt;code&gt;async: true&lt;&#x2F;code&gt;
for my tests. This often causes substantial performance hit, as it prevents
different modules to run in parallel (not single tests, &lt;em&gt;modules&lt;&#x2F;em&gt;, but that is
probably material for another post).&lt;&#x2F;p&gt;
&lt;p&gt;Instead of mocks I prefer to utilise dependency injection. Some people may argue
that &quot;Elixir is FP, not OOP, there is no need for dependency injection&quot;. They
could not be further from truth. DI isn&#x27;t related to OOP, it just have different
form - function arguments. For example, if we want to have function that do
something with time, in particular - current time, then instead of writing:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; my_function&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  do_foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; DateTime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;utc_now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which would require me to use mocks for &lt;code&gt;DateTime&lt;&#x2F;code&gt; or other workarounds to make
tests time-independent. I would do:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; my_function&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; now&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; \\&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; DateTime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;utc_now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  do_foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which still provide me the ergonomics of &lt;code&gt;my_function&#x2F;2&lt;&#x2F;code&gt; as above, but is way
easier to test, as I can pass the date to the function itself. Now I can run
this test in parallel as it will not cause other tests to do weird stuff because
of altered &lt;code&gt;DateTime&lt;&#x2F;code&gt; behaviour.&lt;&#x2F;p&gt;
&lt;p&gt;This approach I use a lot when I am writing some functions that are doing
HTTP(S) requests to external services. I use optional&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#opt-arg&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; keyword list
argument called with super creative name &lt;code&gt;opts&lt;&#x2F;code&gt;. With that, I can pass option
like &lt;code&gt;:host&lt;&#x2F;code&gt; which allows me to use tools like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;danschultzer&#x2F;test_server&quot;&gt;&lt;code&gt;test_server&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; which is great
and it is, in my humble opinion, way better approach than any mocking.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;opt-arg&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Arguments in Elixir never are optional, it is a clever trick from
language authors, but that is probably for another article.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;avoid-ex-machina-factories&quot;&gt;Avoid &lt;code&gt;ex_machina&lt;&#x2F;code&gt; factories&lt;a class=&quot;zola-anchor&quot; href=&quot;#avoid-ex-machina-factories&quot; aria-label=&quot;Anchor link for: avoid-ex-machina-factories&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I have poor experience with tools like &lt;code&gt;ex_machina&lt;&#x2F;code&gt; or similar. These often
bring whole &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;softwareengineering.stackexchange.com&#x2F;q&#x2F;368797&quot;&gt;Banana Gorilla Jungle problem&lt;&#x2F;a&gt; back, just changed a little, as
now instead of just passing data around, we create all needless structures for
sole purpose of test, even when they aren&#x27;t needed for anything.&lt;&#x2F;p&gt;
&lt;p&gt;Start with example from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;beam-community&#x2F;ex_machina#overview&quot;&gt;ExMachina README&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Factory&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # with Ecto&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; ExMachina&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Ecto&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Repo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # without Ecto&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; ExMachina&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; user_factory&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Jane Smith&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      email&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;email&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;email-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-punctuation z-definition z-variable&quot;&gt;#{&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;@example.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;admin&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;other&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; article_factory&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    title &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Use ExMachina! (Part &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-punctuation z-definition z-variable&quot;&gt;#{&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # derived attribute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    slug &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;title_to_slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # associations are inserted when you call `insert`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # derived factory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; featured_article_factory&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    struct!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;      article_factory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        featured&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; comment_factory&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Comment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;It&amp;#39;s great!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For start we can see a single problem there - we do not validate our factories
against our schema changesets. Without additional tests like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Article&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;factory conforms to changeset&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  changeset &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt; @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;changeset&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;{},&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; params_for&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  assert changeset&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;valid?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We cannot be sure that our tests test what we want them to test. And if we pass
custom attribute values in some tests it gets even worse, because we cannot be
sure if these are conforming either.&lt;&#x2F;p&gt;
&lt;p&gt;That mean that our tests may be moot, because we aren&#x27;t testing against real
situations, but against some predefined state.&lt;&#x2F;p&gt;
&lt;p&gt;Another problem is that if we need to alter the behaviour of the factory it can
became quite convoluted. Imagine situation when we want to test if comments by
author of the post have some special behaviour (for example it has some
additional CSS class to be able to mark them in CSS). That require from us to do
some dancing around passing custom attributes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;comments by author are special&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  post &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; insert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  comment &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; insert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;comment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # rest of the test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And this is simplified example. In the past I needed to deal with situations
where I was creating a lot of data to pass through custom attributes to make
test sensible.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, I prefer to do stuff directly in code. Instead of relying on some
&quot;magical&quot; functions provided by some &quot;magical&quot; macros from external library I
can use what I already have - functions in my application.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;comments by author are special&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  post &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; insert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  comment &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; insert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;comment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # rest of the test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Write:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;comments by author are special&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  author &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Users&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;create&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;John Doe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      email&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;john@example.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  post &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Blog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;create_article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Foo bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Foo bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  comment &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Blog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;create_comment_for&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Foo bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # rest of the test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It may be a little bit more verbose, but it makes tests way more readable in my
opinion. You have all details just in place and you know what to expect. And if
you need some piece of data in all (or almost all) tests within
module&#x2F;&lt;code&gt;describe&lt;&#x2F;code&gt; block, then you can always can use &lt;code&gt;setup&#x2F;1&lt;&#x2F;code&gt; blocks.
Alternatively, you can create function per module that will generate data for
you. As long as your test module is self-contained and do not receive &quot;magical&quot;
data out of thin air, it is okay for me. But &lt;code&gt;ex_machina&lt;&#x2F;code&gt; is, in my opinion,
terrible idea brought from Rails world, that make little to no sense in Elixir.&lt;&#x2F;p&gt;
&lt;p&gt;If you &lt;em&gt;really&lt;&#x2F;em&gt; need such factories, then just write your own functions that will
use your contexts instead of relying on another library. For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; ExUnit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Assertions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; create_user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; email&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-constant z-language&quot;&gt; \\ nil&lt;&#x2F;span&gt;&lt;span&gt;, attrs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; \\&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  email &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; email &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin&quot;&gt;#{&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;@example.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  attrs &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;merge&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;attrs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; email&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; email&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  assert &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Users&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;create&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;attrs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# And so on…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This way you do not need to check if all tests use correct validations any
longer, as your system will do that for you. No more surprises related to
dealing with &quot;impossible data&quot;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;property-testing-is-awesome&quot;&gt;Property testing is awesome&lt;a class=&quot;zola-anchor&quot; href=&quot;#property-testing-is-awesome&quot; aria-label=&quot;Anchor link for: property-testing-is-awesome&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Property_testing&quot;&gt;Property based Testing&lt;&#x2F;a&gt; is absurdly wide topic, and this article isn&#x27;t a
place to describe all possibilities of that approach. There are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;propertesting.com&quot;&gt;books&lt;&#x2F;a&gt;
written about this topic. However, it is something I find useful to keep in mind,
that this approach exists and is tremendously useful in many places (not all, do
not try to squeeze square peg into round hole).&lt;&#x2F;p&gt;
&lt;p&gt;Quick example that I can show is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;property &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;valid names starts with alphanumeric and are composed of alphanumeric, underscore, and dash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  check &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          prefix &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;alphanumeric&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; length&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          suffix &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;?a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;..&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;?z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; ?A&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;..&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;?Z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; ?-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; ?_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span&gt; max_length&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;        )&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    changeset &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;      @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;register_changeset&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;{},&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; prefix &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; suffix&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    assert &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-keyword z-operator&quot;&gt;nil ==&lt;&#x2F;span&gt;&lt;span&gt; changeset&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;errors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It checks whether all usernames, that start with alphanumeric character and is
followed by sequence of up to 24 characters containing alphanumeric characters
with addition of dash and underscore, pass through validation.&lt;&#x2F;p&gt;
&lt;p&gt;This test will try to generate &lt;em&gt;random&lt;&#x2F;em&gt; set of possible usernames, and then
check if all of them pass the test. If something fails, then system will try to
reduce found example to create minimal example that fails. It is not fully
deterministic test (the output may depend on randomly selected seed), but if
used correctly with other tests, it will greatly improve confidence in tests.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;parting-words&quot;&gt;Parting words&lt;a class=&quot;zola-anchor&quot; href=&quot;#parting-words&quot; aria-label=&quot;Anchor link for: parting-words&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Tests should be readable, often even more readable than the code itself. Good
test suite can help you with confidence in your changes. In current world, full
of agentic coding, tests became even more important, as with good tests suite
you can give your agents more autonomy.&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, I think that mocking must be destroyed.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Scotty, I need warp speed in three minutes</title>
      <published>2026-04-20T00:00:00+00:00</published>
      <updated>2026-04-20T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/things-about-elixir-you-probably-will-never-need/" type="text/html"/>
      <id>https://hauleth.dev/post/things-about-elixir-you-probably-will-never-need/</id><summary>My journey into optimising Elixir codebase of Ultravisor (my fork of Supabase&#x27;s
Supavisor).

This story is not about a goal, but ~~friends~~ optimisations we met along the
way.
</summary><content type="html">&lt;p&gt;In my last larger gig I worked on fascinating project - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;supabase&#x2F;supavisor&quot;&gt;Postgres connection
pooler written in Elixir&lt;&#x2F;a&gt;. Unfortunately, due to different
circumstances, this project burned me out to the ground. However what doesn&#x27;t
kill you &lt;del&gt;is crap not a weapon&lt;&#x2F;del&gt; can become great learning experience.&lt;&#x2F;p&gt;
&lt;p&gt;Most of my achievements in this project were related to performance. This
project contains &lt;strong&gt;very&lt;&#x2F;strong&gt; tight loop in form of query handler, that needed to
run hundreds of thousands times per second per user connection. That mean that
this functions are &lt;em&gt;very&lt;&#x2F;em&gt; sensitive to even slightest performance changes. And
that was my task - to find potential improvements that can be made to make this
codebase be much faster.&lt;&#x2F;p&gt;
&lt;p&gt;After departing from Supabase I liked the project so much (mostly as learning
ground) that I have created my own fork. There, unrestrained from all business
side of the project I could focus purely on squeezing as much of performance as
I can. This project now lives as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Ultravisor&#x2F;ultravisor&quot;&gt;Ultravisor&lt;&#x2F;a&gt; - it is still nowhere near being
done in a way that I like, but I still go back to work on it from time to time
to find potential performance improvements.&lt;&#x2F;p&gt;
&lt;p&gt;This is a story of things that I have done and learned during that journey.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Beware&lt;&#x2F;strong&gt;: It is retrospection, so in some places my memory may be not the
best.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Here I need to provide some explanation first, about how Ultravisor works with
database connections. It provides 2 modes of operation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;session&lt;&#x2F;code&gt; - where each connection from user to Ultravisor checks out one
connection from Ultravisor to database. It checks out once, at the start
of connection, and then holds connection until the end;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;transaction&lt;&#x2F;code&gt; - where on connection there is nothing done. Client connects to
the Ultravisor and can keep that connection indefinitely without ever
bothering database. Database connection is checked out &lt;em&gt;only&lt;&#x2F;em&gt; when there is
some request from user and is returned to the pool as soon as that result of
that query is returned and database is ready for next one.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;While &lt;code&gt;session&lt;&#x2F;code&gt; mode is quite on par with other implementations of connection
pooling for Postgres, &lt;code&gt;transaction&lt;&#x2F;code&gt; mode is where performance is lacking and is
the main focus is put. In whole article (unless mentioned otherwise) I will
speak about &lt;code&gt;transaction&lt;&#x2F;code&gt; mode of Ultravisor.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lesson-flame-graphs-and-call-tracing-is-essential&quot;&gt;Lesson: Flame graphs and call tracing is essential&lt;a class=&quot;zola-anchor&quot; href=&quot;#lesson-flame-graphs-and-call-tracing-is-essential&quot; aria-label=&quot;Anchor link for: lesson-flame-graphs-and-call-tracing-is-essential&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Pretty obvious thing, but still valuable lesson for any performance
optimisation endeavour. For that the great thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Stratus3D&quot;&gt;Trevor Brown&lt;&#x2F;a&gt;
and his awesome project &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Stratus3D&#x2F;eflambe&quot;&gt;eFlambè&lt;&#x2F;a&gt;. This helped a lot in tracing hot
points in the running code.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately this project seems to be less active recently and has some missing
features, like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Stratus3D&#x2F;eflambe&#x2F;issues&#x2F;48&quot;&gt;listening for given duration instead of function calls
count&lt;&#x2F;a&gt;. This can be partially
fixed by simply listening for count of calls to &lt;code&gt;handle_event&#x2F;4&lt;&#x2F;code&gt; function given
times and then running &lt;code&gt;cat *.bggg&lt;&#x2F;code&gt; to concatenate all files into larger trace.
That has disadvantages, but at least it was workable within &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;speedoscope.app&quot;&gt;Speedoscope&lt;&#x2F;a&gt;
which I also highly recommend to anyone who needs to work on such optimisation.&lt;&#x2F;p&gt;
&lt;p&gt;While flame graphs are awesome, there is cost to gathering them with eFlambè -
it greatly affects performance. Fortunately Erlang has some built-in tools that
have lesser performance impact, and the &quot;most modern&quot; of these is
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;tprof.html&quot;&gt;&lt;code&gt;tprof&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. This tool is pretty easy to use, but is less detailed than
eFlambè. But even with that limitation, it provides superb insight into stuff
that has greatest impact on performance. It make it easier to work on long
running processes, as it work asynchronously, so you can &quot;manually&quot; decide how
long you want to trace your process.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;&#x2F;strong&gt; Knowing where your bottlenecks are is essential for performance
optimisations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lesson-doing-less-can-improve-performance&quot;&gt;Lesson: Doing less can improve performance&lt;a class=&quot;zola-anchor&quot; href=&quot;#lesson-doing-less-can-improve-performance&quot; aria-label=&quot;Anchor link for: lesson-doing-less-can-improve-performance&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Obvious thing that need to be stated - doing nothing is faster than doing
something. Extracting amount of data sent over given socket using
&lt;code&gt;:inet.getstat&#x2F;2&lt;&#x2F;code&gt; call is fast, but not free. That involves some waiting for
response from either port or process handling connection, which introduces
slowdown. Two possible solutions there are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Do not gather that metric at all - sensible, but not feasible, especially when
you use that metric to charge your users.&lt;&#x2F;li&gt;
&lt;li&gt;Gather that data less often.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The approach I have taken there is obviously 2., and the solution is dumb
simple - debouncer.&lt;&#x2F;p&gt;
&lt;p&gt;Debouncing is an interesting technique often used in user interfaces where you
accept some event, and then for some period you ignore repeated events. The
reason for that is that our interfaces may have flaws that send repeated events
one after another.&lt;&#x2F;p&gt;
&lt;p&gt;In this case Ultravisor tries to store amount of sent data after each query, but
that can get expensive for many short queries. Instead, I have implemented simple
per-process debouncer:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Ultravisor&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Debouncer&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; debounce&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; time&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; \\&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;span&gt;, func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    current &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;monotonic_time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;millisecond&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    key &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;debounce&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span&gt;prev&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; ret&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; prev &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; time &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; current &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;      _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ret &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;.()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;        Process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;put&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span&gt;current&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; ret&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This stores returned data in process dictionary (per-process mutable space with
quick access) and if there was no call in given time-period, then we process
data again. This is safe way to do so, as &lt;code&gt;:inet.getstat&#x2F;2&lt;&#x2F;code&gt; will always return
amount of data that socket processed since it started, so data between calls
will be accounted.&lt;&#x2F;p&gt;
&lt;p&gt;Before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 79401.392762 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After (10ms of debouncing):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 80069.646510 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After (100ms of debouncing):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 80568.825937 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;&#x2F;strong&gt;: Doing noting is more performant than doing something. Sometimes
doing nothing can be quite easy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lesson-telemetry-is-not-free&quot;&gt;Lesson: Telemetry is not free&lt;a class=&quot;zola-anchor&quot; href=&quot;#lesson-telemetry-is-not-free&quot; aria-label=&quot;Anchor link for: lesson-telemetry-is-not-free&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;When working on most projects, especially Phoenix-based, one can slap
&lt;code&gt;:telemetry.execute&#x2F;3&lt;&#x2F;code&gt; calls everywhere and notice no performance degradation&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#telemetry&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
Unfortunately, when you do hundreds of thousands calls a second - that is not a
case.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;telemetry&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;For unaware readers - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;beam-telemetry&#x2F;telemetry&quot;&gt;Telemetry&lt;&#x2F;a&gt; is Erlang event dispatching
system for observability events.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;In this project the metrics are exposed in Prometheus&#x2F;OpenMetrics format, which
means that there need to be collection system within the application. In BEAM
applications the standard way to implement that is to use ETS tables to store
recorded values. Fortunately there are libraries to handle that for you, and for
the longest time &quot;gold standard&quot; for it was &lt;code&gt;telemetry_prometheus_core&lt;&#x2F;code&gt; library
created by Telemetry core team.&lt;&#x2F;p&gt;
&lt;p&gt;While for most projects that library is performant enough (because metrics
aren&#x27;t recorded in tight loops), in case of this project that was not a case.
There, metrics gathering is still one of the hottest spots in the codebase, even
with all improvements that have been done.&lt;&#x2F;p&gt;
&lt;p&gt;Excerpt from &lt;code&gt;tprof&lt;&#x2F;code&gt; profile:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Function&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;Calls count&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;Per call (μs)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;Percentage&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Peep.EventHandler.store_metrics&#x2F;5&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;1421911&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.13&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;4.21%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Peep.Storage.Striped.insert_metric&#x2F;5&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;904852&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.26&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;5.11%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;This is with awesome library &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rkallos&#x2F;peep&quot;&gt;Peep&lt;&#x2F;a&gt; by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rkallos&quot;&gt;Richard Kallos&lt;&#x2F;a&gt;. When using
&lt;code&gt;telemetry_prometheus_core&lt;&#x2F;code&gt; it was simply the most expensive thing in whole
loop. Just replacing metrics gathering library with Peep gave us about 2x bump
in TPS.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;&#x2F;strong&gt; Telemetry handler can matter in tight loops. Fast metrics gathering
isn&#x27;t easy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lesson-records-instead-of-maps-or-structs&quot;&gt;Lesson: Records instead of maps or structs&lt;a class=&quot;zola-anchor&quot; href=&quot;#lesson-records-instead-of-maps-or-structs&quot; aria-label=&quot;Anchor link for: lesson-records-instead-of-maps-or-structs&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Elixir uses structs for structured data. That gives a lot nice features wrt. hot
code reloads, compilation graph dependencies, and other. However, because
structs are maps, there is a cost. Maps have O(log n) access time to the fields,
this is how maps are constructed in memory. While smaller maps have slightly
different (better in most cases) characteristics, there is strict requirement
that you keep your structure with less than 31 fields&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#fields&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and it still has
slight memory overhead. The alternative is to use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;Record.html&quot;&gt;records&lt;&#x2F;a&gt;. These have better
performance characteristic (always constant) irrelevant of the amount of fields
at the cost of being slightly more rigid (records are tuple based) and less
convenient to use (experience may vary). Additional advantage in my opinion is
that it is harder to add incorrect field by using &lt;code&gt;Map&lt;&#x2F;code&gt; module.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;fields&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Current (OTP 28) limit for small map is 32 keys, but Elixir uses one
key for struct name, hence 31 fields is the limit.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Before you will run and change all structs in your system to records, just
remember - most of the time the difference doesn&#x27;t matter - just use structures.&lt;&#x2F;p&gt;
&lt;p&gt;Before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 81765.266264 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 82147.855889 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;&#x2F;strong&gt; &lt;code&gt;Record&lt;&#x2F;code&gt;s are super handy when you need to squeeze each bit of
performance. It doesn&#x27;t provide much, but these adds up.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lesson-ets-tables-are-super-fast-but-not-always&quot;&gt;Lesson: ETS tables are super fast, but not always&lt;a class=&quot;zola-anchor&quot; href=&quot;#lesson-ets-tables-are-super-fast-but-not-always&quot; aria-label=&quot;Anchor link for: lesson-ets-tables-are-super-fast-but-not-always&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.erlang.org&#x2F;doc&#x2F;apps&#x2F;stdlib&#x2F;ets.html&quot;&gt;ETS&lt;&#x2F;a&gt; is Erlang&#x27;s built-in module for storing key-value data in mutable way.
Like built-in Redis. This structure allows for sharing some data in a way, that
is easy to access from different parts of the system. One example of system that
is using ETS for storing their information is Telemetry (mentioned above).&lt;&#x2F;p&gt;
&lt;p&gt;While for 99% of the use cases Telemetry will be fast enough, it has some
problems with tight loops. Main problem is that it will always copy data from
table to the caller process. That mean that it can put high memory pressure on
the process that tries to retrieve data.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately Erlang supports another mechanism for storing globally accessible
data - &lt;code&gt;persistent_term&lt;&#x2F;code&gt;. Of course, there is no such thing as &quot;free lunch&quot; so
it has substantial disadvantage. It works poorly&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#pt&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; with data that changes
often, as removing or changing data in a key will require walk through all
processes to copy data from it to processes that may use it into process memory.
However, Telemetry handlers should not change a lot, you should just set them
once as soon as your system start, and then ideally they will not change ever
again.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;pt&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;There is slight optimisation that makes it fast in some cases (single
word values, like atoms), but that is not the case there, so we can ignore
that.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Before&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#lower-tps&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 76914.004685 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 78479.006634 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;lower-tps&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;If you wonder why these results are lower than in previous
section, it is because test conditions are identical only per section, not
cross sections. In this particular case I have run benchmark while
collecting metrics (to show difference in &lt;code&gt;persistent_term&lt;&#x2F;code&gt; change) while
other are run without metrics to not pollute results.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;&#x2F;strong&gt; &lt;code&gt;persistent_term&lt;&#x2F;code&gt; is awesome and superfast, so if you know that
you have some data that will probably never change and will be requested
&lt;em&gt;constantly&lt;&#x2F;em&gt;, then it may be good place to store that data.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lesson-calling-your-genservers-is-fast-but-not-90k-times-per-second-fast&quot;&gt;Lesson: Calling your &lt;code&gt;GenServer&lt;&#x2F;code&gt;s is fast, but not 90k times per second fast&lt;a class=&quot;zola-anchor&quot; href=&quot;#lesson-calling-your-genservers-is-fast-but-not-90k-times-per-second-fast&quot; aria-label=&quot;Anchor link for: lesson-calling-your-genservers-is-fast-but-not-90k-times-per-second-fast&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;One of the interesting observations that I have spotted is that if there are
longer running queries. Ones that send more data over the network than just
simple short responses, then the difference between Ultravisor and &quot;state of the
art&quot; tools like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pgbouncer.org&quot;&gt;PgBouncer&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pgdog.dev&quot;&gt;PgDog&lt;&#x2F;a&gt; (written in non-managed languages
like C and Rust) is much smaller. Obviously it is still there, but it is on par,
not substantially off.&lt;&#x2F;p&gt;
&lt;p&gt;I needed to dig more, what can be the cause of such strange behaviour. The
reason was found in place where I least expected it - checking out database
connection to be used.&lt;&#x2F;p&gt;
&lt;p&gt;Flame graph showed that almost third of the time is spent on checking out
database connections. Most of that time is spent in 2 function calls, both
of them are internally &lt;code&gt;gen_statem&lt;&#x2F;code&gt; calls and in both most time is spent on
sleeping (aka, waiting for reply).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;things-about-elixir-you-probably-will-never-need&#x2F;sleep.png&quot; alt=&quot;Image showing left-heavy flamegraph of the profiled application&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now, this is hard thing to optimise, as in Elixir there is no mutability
(almost, we will get there). This mean that if I want some form of shared queue
of processes, then I need to use separate process to keep state of the queue for
us, and then do &lt;code&gt;GenServer&lt;&#x2F;code&gt; calls to fetch that state. What I did in such
situation? What any unreasonable Elixir developer obsessed with performance
would do - NIF&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#ets&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;ets&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;I wanted to use ETS there, but for that to work it lacks function like
&lt;code&gt;ets:take&#x2F;2&lt;&#x2F;code&gt; that would return only one element from the tables with type
&lt;code&gt;bag&lt;&#x2F;code&gt; or &lt;code&gt;duplicate_bag&lt;&#x2F;code&gt;. Or any other form of just taking out any (possibly
random) element from ETS table in atomic way.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The implementation is rather basic wrapper over &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;1.94.0&#x2F;std&#x2F;collections&#x2F;struct.VecDeque.html&quot;&gt;&lt;code&gt;VecDeque&lt;&#x2F;code&gt;s&lt;&#x2F;a&gt;
that allow popping single element from that queue without any message passing.
The implementation is very crude, nowhere production ready. It doesn&#x27;t provide
any form of worker restarts or anything, but works quite well as PoC of what is
possible.&lt;&#x2F;p&gt;
&lt;p&gt;New queue also provides a way to store additional &quot;metadata&quot; alongside the
worker PID. This allows me to store DB connection socket next to connection
process, which removes need for additional call to extract that data to pass
requests directly to other DB, without copying data between processes.&lt;&#x2F;p&gt;
&lt;p&gt;Before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 83619.640673 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tps = 94191.475386 (without initial connection time)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;&#x2F;strong&gt; Sometimes one need to get creative to get around platform
limitations. This may require some pesky NIFs though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusions&quot; aria-label=&quot;Anchor link for: conclusions&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Optimising such project was enormous fun and I think that at the current state
there is nothing extra that can be done to optimise it more without optimising
generated JIT-ed native code or optimising Erlang scheduler.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;things-about-elixir-you-probably-will-never-need&#x2F;final.png&quot; alt=&quot;Final flamegraph of application&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There are some flags, that affect performance, but as it is currently unclear
why these work at all (probably it is related more to the OS scheduler rather
than Erlang performance), I left them out of this article for now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;post-scriptum-good-tooling-helps-a-lot&quot;&gt;Post Scriptum: Good tooling helps a lot&lt;a class=&quot;zola-anchor&quot; href=&quot;#post-scriptum-good-tooling-helps-a-lot&quot; aria-label=&quot;Anchor link for: post-scriptum-good-tooling-helps-a-lot&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Just after I have started that optimisation project after leaving Supabase I
started using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.jj-vcs.dev&#x2F;latest&#x2F;&quot;&gt;Jujutsu&lt;&#x2F;a&gt; for version control. That one thing helped me &lt;strong&gt;a
lot&lt;&#x2F;strong&gt; with being able to have separate branches&#x2F;PRs for each of the changes,
while at the same being able to work with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;steveklabnik.github.io&#x2F;jujutsu-tutorial&#x2F;advanced&#x2F;simultaneous-edits.html&quot;&gt;mega-merge&lt;&#x2F;a&gt; of them all.&lt;&#x2F;p&gt;
&lt;p&gt;That allows me to profile code with all other noise removed, while still
exposing the changes as separate reviewable units. Without that support I would
need to decipher what have already been changed and&#x2F;or removed from the profile.&lt;&#x2F;p&gt;
&lt;p&gt;Additional feature that I heavily used there is &quot;anonymous branching&quot;. As when
working with JJ I do not need to create new name for each branch that I want to
try. It was way easier to implement one idea, then just do &lt;code&gt;jj new @-&lt;&#x2F;code&gt; (which
branches off at the commit that is parent of the current one) and just implement
alternative idea. I used that constantly to compare ideas and reject failed
concepts.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Jeopardy! world</title>
      <published>2025-07-28T00:00:00+00:00</published>
      <updated>2025-07-28T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/jeopardy-world/" type="text/html"/>
      <id>https://hauleth.dev/post/jeopardy-world/</id><summary type="html"><p>Some time ago, there was an anime available on Netflix — <em>Godzilla Singular
Point</em>. It wasn't a spectacular success, but it featured a plot device that I
think reflects something increasingly common today: you need to know the answer
to your question before you can ask it.</p>
<p>This is something I see all the time in the current wave of AI hype. You need to
know what the answer <em>should</em> be before you can write a useful prompt.</p></summary><content type="html">&lt;p&gt;Some time ago, there was an anime available on Netflix — &lt;em&gt;Godzilla Singular
Point&lt;&#x2F;em&gt;. It wasn&#x27;t a spectacular success, but it featured a plot device that I
think reflects something increasingly common today: you need to know the answer
to your question before you can ask it.&lt;&#x2F;p&gt;
&lt;p&gt;This is something I see all the time in the current wave of AI hype. You need to
know what the answer &lt;em&gt;should&lt;&#x2F;em&gt; be before you can write a useful prompt.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;The issue I have with many AI use cases is this: unless you have specialized
knowledge about the topic you&#x27;re asking about, you can&#x27;t reliably tell the
difference between a solid AI answer and complete nonsense.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve had a few discussions about this on various Discord servers. The example I
often use is this simple question posed to an AI:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does 6 character long identification number, that contains digits and upper
case letters (with exception to 0, O, 1, I, and L) is enough to randomly
assign unique identification numbers for 10 million records?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;You can see for yourself answer from ChatGPT &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;chatgpt.com&#x2F;share&#x2F;68879fe7-d4e0-8007-9a30-3a9e2ace791d&quot;&gt;there&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;At first glance, the answer looks valid and sensible. The math checks out. It
calculates the number of available combinations correctly. Everything seems
&lt;em&gt;fine&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;BUT…&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There is huge issue there, and probably most of the people who have been working
with basic statistic or cryptography will notice it. ChatGPT (and any other AI
that I have tested out) fail to notice very important word there&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] randomly […]&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This single word invalidates the entire reasoning, despite the correct
calculations. Because of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Birthday_problem&quot;&gt;birthday problem&lt;&#x2F;a&gt;, the answer isn&#x27;t feasible.
While it&#x27;s technically possible to assign a unique ID to every record, doing so
randomly introduces a high probability of collisions.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;At around 35,000 generated IDs, there&#x27;s already a 50% chance of a collision&lt;&#x2F;li&gt;
&lt;li&gt;At around 90,000, the chance of at least one duplicate reaches 99%&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So even though the math is correct, the logic fails under the randomness constraint.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jeopardy-world&quot;&gt;&lt;em&gt;Jeopardy!&lt;&#x2F;em&gt; world&lt;a class=&quot;zola-anchor&quot; href=&quot;#jeopardy-world&quot; aria-label=&quot;Anchor link for: jeopardy-world&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This is my main issue with AI tools: if you already have knowledge about the
subject, you don’t really need to ask the AI. But if you don’t have that
knowledge, you have no reliable way of knowing whether the answer makes sense or
not. It’s like playing &lt;em&gt;Jeopardy!&lt;&#x2F;em&gt; — you need to know the answer before you can
phrase the right question.&lt;&#x2F;p&gt;
&lt;p&gt;In my view, AI is most useful in areas where the results can be quickly reviewed
and discarded if needed. That’s why the whole “vibe coding” (aka slop
generation) approach falls short. If you don’t have a good sense of what the
output should look like, you probably don’t have the expertise to verify it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.businessinsider.com&#x2F;replit-ceo-apologizes-ai-coding-tool-delete-company-database-2025-7?op=1&quot;&gt;And gods forbid you from allowing AI to do anything on production&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Who Watches Watchmen? - Part 2</title>
      <published>2023-11-14T00:00:00+00:00</published>
      <updated>2023-11-14T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/who-watches-watchmen-ii/" type="text/html"/>
      <id>https://hauleth.dev/post/who-watches-watchmen-ii/</id><summary>Continuation of travel into making systemd to work for us, not against us. This
time we will talk about socket activation and how to make our application run
only when we need it to run.
</summary><content type="html">&lt;p&gt;This is continuation of &lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;who-watches-watchmen-i&#x2F;&quot;&gt;Part I&lt;&#x2F;a&gt; where I described the basics of the
supervising BEAM applications with systemd and how to create basic, secure
service for your Elixir application with it. In this article I will assume that
you have read &lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;who-watches-watchmen-i&#x2F;&quot;&gt;the previous one&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;We already have our super simple service description. Just to refresh your
memory, it is the &lt;code&gt;hello.service&lt;&#x2F;code&gt; file once again:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Requires&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;network.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;notify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;WatchdogSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;1min&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# We need to add capability to be able to bind on port 80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;CapabilityBoundingSet&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;CAP_NET_BIND_SERVICE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Hardening&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;PrivateDevices&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ERL_CRASH_DUMP_SECONDS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, there is one small problem. It allows our service to listen on &lt;strong&gt;any&lt;&#x2F;strong&gt;
restricted port, not just &lt;code&gt;80&lt;&#x2F;code&gt; that we want to listen on. This can be
troublesome as an attacker, that gains RCE on our server, can then capture any
traffic on any port that we do not want to open (for example exposing port 22
using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;ssh.html&quot;&gt;&lt;code&gt;ssh&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; module).&lt;&#x2F;p&gt;
&lt;p&gt;It would be nice if we could somehow inject sockets for only the ports we want
to listen to into our application.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;socket-passing&quot;&gt;Socket passing&lt;a class=&quot;zola-anchor&quot; href=&quot;#socket-passing&quot; aria-label=&quot;Anchor link for: socket-passing&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Thanks to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd.socket.html&quot;&gt;&lt;code&gt;systemd.socket&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; feature we can achieve that
with a little work on our side.&lt;&#x2F;p&gt;
&lt;p&gt;First we need to create new unit named &lt;code&gt;hello.socket&lt;&#x2F;code&gt; next to our
&lt;code&gt;hello.service&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Listening socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Requires&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;sockets.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Socket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ListenStream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;both&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ReusePort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;NoDelay&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will create a socket connected to TCP 80 (because we used &lt;code&gt;ListenStream=&lt;&#x2F;code&gt;,
and TCP is the stream protocol). By default it will bind that socket to a
service named the same as our socket, so now we need to edit our &lt;code&gt;hello.service&lt;&#x2F;code&gt;
a little bit:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Requires&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;network.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;notify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;WatchdogSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;1min&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# See, we no longer need to insecurely allow binding to any port&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# CapabilityBoundingSet=CAP_NET_BIND_SERVICE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Hardening&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;PrivateDevices&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ERL_CRASH_DUMP_SECONDS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we need to modify our &lt;code&gt;Hello.Application.cowboy_opts&#x2F;0&lt;&#x2F;code&gt; to handle the socket
which is passed to us a file descriptor:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# hello&#x2F;application.ex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fds &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt; :systemd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;listen_fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    children &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span&gt;scheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;)},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Drainer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; refs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Supervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start_link&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;children&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;one_for_one&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # If there are no sockets passed to the application, then start listening on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # the port specified by the `PORT` environment variable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;([])&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;span&gt;port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;to_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get_env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;))]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # If there are any socket passed, then use first one&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;([&lt;&#x2F;span&gt;&lt;span&gt;socket &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;])&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fd &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      case&lt;&#x2F;span&gt;&lt;span&gt; socket &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Sockets can be named, which will be passed as the second element in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # a tuple&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span&gt;fd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Or unnamed, and then it will be just the file descriptor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fd &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;inet6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; # (1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # (2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      fd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; fd       &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# (3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;Systemd sockets are IPv6 enabled (we explicitly said that we want to listen
on both). That means, that we need to mark our connection as an INET6
connection. This will not affect IPv4 (INET) connections.&lt;&#x2F;li&gt;
&lt;li&gt;We are required to pass &lt;code&gt;:port&lt;&#x2F;code&gt; key, but its value will be ignored, so we
just pass &lt;code&gt;0&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We pass the file descriptor that will be then passed to the Cowboy listener.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Now when we will start our service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl start hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will be available at &lt;code&gt;https:&#x2F;&#x2F;localhost&#x2F;&lt;&#x2F;code&gt; while still running as an
unprivileged user.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;multiple-ports&quot;&gt;Multiple ports&lt;a class=&quot;zola-anchor&quot; href=&quot;#multiple-ports&quot; aria-label=&quot;Anchor link for: multiple-ports&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The question may arise - how to allow our service to listen on more than one
port, for example you want to have your website available as HTTPS alongside
&quot;regular&quot; HTTP. This means that our application needs to listen on two
restricted ports:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;80 - for HTTP&lt;&#x2F;li&gt;
&lt;li&gt;443 - for HTTPS&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now we need to slightly modify a little our socket service and add another one.
First rename our &lt;code&gt;hello.socket&lt;&#x2F;code&gt; to &lt;code&gt;hello-http.socket&lt;&#x2F;code&gt; and add a line
&lt;code&gt;Service=hello.service&lt;&#x2F;code&gt; and &lt;code&gt;FileDescriptorName=http&lt;&#x2F;code&gt; to &lt;code&gt;[Socket]&lt;&#x2F;code&gt; section, so
we end with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;HTTP Socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Requires&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;sockets.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Socket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# We declare the name of the file descriptor here to simplify extraction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# in the application afterwards. By default it will be the socket name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# (so `hello-http` in our case), but `http` is much cleaner.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;FileDescriptorName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;http&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ListenStream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;both&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ReusePort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;NoDelay&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we create a similar file, but for HTTPS named &lt;code&gt;hello-https.socket&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;HTTPS Socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Requires&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;sockets.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Socket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;FileDescriptorName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;https&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ListenStream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;443&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;both&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ReusePort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;NoDelay&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we add the dependency on both of our sockets to the &lt;code&gt;hello.service&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;After&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;hello-http.socket hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;BindTo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;hello-http.socket hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Hardening&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;PrivateDevices&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ERL_CRASH_DUMB_SECONDS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we need to somehow differentiate between our sockets in the
&lt;code&gt;Hello.Application&lt;&#x2F;code&gt;, so we will be able to pass the proper FD to each of the
listeners. The &lt;code&gt;:systemd.listen_fds&#x2F;0&lt;&#x2F;code&gt; will return a list of file descriptors,
and if they are named, the format will be a 2-tuple where the first element is
the file descriptor and the second is the name as a string:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# hello&#x2F;application.ex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fds &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt; :systemd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;listen_fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    router &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    children &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; router&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;https&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; router&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        keyfile&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;path&#x2F;to&#x2F;keyfile.pem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        certfile&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;path&#x2F;to&#x2F;certfile.pem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        dhfile&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;path&#x2F;to&#x2F;dhfile.pem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Drainer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; refs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Supervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start_link&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;children&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;one_for_one&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; List&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;keyfind&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;fds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # If there is socket passed for given protocol, then use that one&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span&gt;fd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; ^protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;        [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;inet6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          fd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;        ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # If there are no sockets passed to the application that match&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # the protocol, then start listening on the port specified by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # `PORT_{protocol}` environment variable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;      _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;        [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;to_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get_env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;PORT_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin&quot;&gt;#{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;        ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now our application will listen on both - HTTP and HTTPS, despite running as
unprivileged user.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;socket-activation&quot;&gt;Socket activation&lt;a class=&quot;zola-anchor&quot; href=&quot;#socket-activation&quot; aria-label=&quot;Anchor link for: socket-activation&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now, that we can inject sockets to our application with ease we can achieve even
more fascinating feature - socket activation.&lt;&#x2F;p&gt;
&lt;p&gt;Some of you may be using &lt;code&gt;inetd&lt;&#x2F;code&gt; in the past, that allows you to dynamically start
processes on network requests. It is quite an interesting tool that detects
traffic on certain ports, then spawns a new process to handle it, passing data
to and from that process via &lt;code&gt;STDIN&lt;&#x2F;code&gt; and &lt;code&gt;STDOUT&lt;&#x2F;code&gt;. There was a quirk though, it
required the spawned process to shutdown after it handled the request and it was
starting a new instance for each request. That works poorly with VMs like BEAM
that have substantial startup time and are expected to be long-running systems.
BEAM is capable of handling network requests on it&#x27;s own.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately for us, the way that we have implemented our systemd service is all
that we need to have our application dynamically activated. To observe that we
just need to shutdown everything:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl stop hello-http.socket hello-https.socket hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now relaunch &lt;strong&gt;only the sockets&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl start hello-http.socket hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can check, that our service is not running:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ systemctl status hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;● hello.service - Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Loaded: loaded (&#x2F;usr&#x2F;local&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;hello.service; static; vendor preset: enabled)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Active: inactive (dead)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TriggeredBy: ● hello-http.socket ● hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see the &lt;code&gt;TriggeredBy&lt;&#x2F;code&gt; section that tells us, that this service will be
started by one of the sockets listed there. Let&#x27;s see what will happen when we
will try to request anything from our application:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ curl http:&#x2F;&#x2F;localhost&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hello World!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see that we got a response from our application. This mean that our
application must have started, and indeed when we check:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ systemctl status hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;● hello.service - Hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Loaded: loaded (&#x2F;usr&#x2F;local&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;hello.service; static; vendor preset: enabled)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Active: active (running) since Thu 2022-02-03 13:20:27 CET; 4s ago&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TriggeredBy: ● hello-http.socket ● hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Main PID: 1106 (beam.smp)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Tasks: 19 (limit: 1136)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Memory: 116.7M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     CGroup: &#x2F;system.slice&#x2F;hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             ├─1106 &#x2F;opt&#x2F;hello&#x2F;erts-12.2&#x2F;bin&#x2F;beam.smp -- -root &#x2F;opt&#x2F;hello -progname erl -- -home &#x2F;run&#x2F;hello -- -noshell -s elixir start_cli -mode embedded -setcookie CR63SVI6L5JAMJSDL3H4XPNMOPHEWSV2FPHCHCAN65CY6ASHMXBA==== -sname hello -c&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             └─1138 erl_child_setup 1024&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It seems to be running, and if we stop it, then we will get information that it
still can be activated by our sockets:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl stop hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Warning: Stopping hello.service, but it can still be activated by:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hello-http.socket hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That means, that systemd is still listening on the sockets that we defined, even
when our application is down, and will start our application again as soon as
there are any incoming requests.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s test that out again:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ curl http:&#x2F;&#x2F;localhost&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hello World!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ systemctl status hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;● hello.service - Hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Loaded: loaded (&#x2F;usr&#x2F;local&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;hello.service; static; vendor preset: enabled)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Active: active (running) since Thu 2022-02-03 13:22:27 CET; 4s ago&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TriggeredBy: ● hello-http.socket ● hello-https.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Main PID: 3452 (beam.smp)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Tasks: 19 (limit: 1136)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Memory: 116.7M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     CGroup: &#x2F;system.slice&#x2F;hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             ├─3452 &#x2F;opt&#x2F;hello&#x2F;erts-12.2&#x2F;bin&#x2F;beam.smp -- -root &#x2F;opt&#x2F;hello -progname erl -- -home &#x2F;run&#x2F;hello -- -noshell -s elixir start_cli -mode embedded -setcookie CR63SVI6L5JAMJSDL3H4XPNMOPHEWSV2FPHCHCAN65CY6ASHMXBA==== -sname hello -c&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             └─3453 erl_child_setup 1024&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our application got launched again, automatically, just by the fact that
there was incoming TCP connection.&lt;&#x2F;p&gt;
&lt;p&gt;Does it work for HTTPS connection as well?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl stop hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ curl -k https:&#x2F;&#x2F;localhost&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hello World!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It seems so. Independently of which port we try to reach our application on, it
will be automatically launched for us and the connection will be properly
handled. Do note that systemd will not shut down our process after serving the
request. It will continue to run from that point forward.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I know that it took quite while since the last post (ca. 1.5 years), but I hope
that I will be able to write the final part much sooner than this.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;who-watches-watchmen-i&#x2F;&quot;&gt;Part 1 - Basics, security, and FD passing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;who-watches-watchmen-ii&#x2F;.&#x2F;#top&quot;&gt;Part 2 - Socket activation (this one)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Part 3 - Logging&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>How much memory is needed to run 1M Erlang processes?</title>
      <published>2023-06-10T00:00:00+00:00</published>
      <updated>2023-06-10T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/beam-process-memory-usage/" type="text/html"/>
      <id>https://hauleth.dev/post/beam-process-memory-usage/</id><summary>How to not write benchmarks</summary><content type="html">&lt;p&gt;Recently &lt;a rel=&quot;external&quot; title=&quot;How Much Memory Do You Need to Run 1 Million Concurrent Tasks?&quot; href=&quot;https:&#x2F;&#x2F;pkolaczk.github.io&#x2F;memory-consumption-of-async&#x2F;&quot;&gt;benchmark for concurrency implementation in different
languages&lt;&#x2F;a&gt;. In this article &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pkolaczk&quot;&gt;Piotr Kołaczkowski&lt;&#x2F;a&gt; used Chat GPT to
generate the examples in the different languages and benchmarked them. This was
poor choice as I have found this article and read the Elixir example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tasks &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt;num_tasks &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;        Task&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;async&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;fn -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;            :timer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        end&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Task&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await_many&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;infinity&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And, well, it&#x27;s pretty poor example of BEAM&#x27;s process memory usage, and I am
not talking about the fact that it uses 4 spaces for indentation.&lt;&#x2F;p&gt;
&lt;p&gt;For 1 million processes this code reported 3.94 GiB of memory used by the process
in Piotr&#x27;s benchmark, but with little work I managed to reduce it about 4 times
to around 0.93 GiB of RAM usage. In this article I will describe:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How I did that&lt;&#x2F;li&gt;
&lt;li&gt;Why the original code was consuming so much memory&lt;&#x2F;li&gt;
&lt;li&gt;Why in the real world you probably should not optimise like I did here&lt;&#x2F;li&gt;
&lt;li&gt;Why using ChatGPT to write benchmarking code sucks (TL;DR because that will
nerd snipe people like me)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-are-erlang-processes&quot;&gt;What are Erlang processes?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-are-erlang-processes&quot; aria-label=&quot;Anchor link for: what-are-erlang-processes&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Erlang is &lt;del&gt;well&lt;&#x2F;del&gt; known of being language which support for concurrency is
superb, and Erlang processes are the main reason for that. But what are these?&lt;&#x2F;p&gt;
&lt;p&gt;In Erlang &lt;em&gt;process&lt;&#x2F;em&gt; is the common name for what other languages call &lt;em&gt;virtual
threads&lt;&#x2F;em&gt; or &lt;em&gt;green threads&lt;&#x2F;em&gt;. These have small neat twist - each of the process
is isolated from the rest and these processes can communicate only via message
passing. That gives Erlang processes 2 features that are rarely spotted in other
implementations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Failure isolation - bug, unhandled case, or other issue in single process will
not directly affect any other process in the system. VM can send some messages
due to process shutdown, and other processes may be killed because of that,
but by itself shutting down single process will not cause problems in any
process not related to that.&lt;&#x2F;li&gt;
&lt;li&gt;Location transparency - process can be spawned locally or on different
machine, but from the viewpoint of the programmer, there is no difference.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The above features and requirements results in some design choices, but for our
purpose only one is truly needed today - each process have separate and (almost)
independent memory stack from any other process.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;process-dictionary&quot;&gt;Process dictionary&lt;a class=&quot;zola-anchor&quot; href=&quot;#process-dictionary&quot; aria-label=&quot;Anchor link for: process-dictionary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Each process in Erlang VM has dedicated &lt;em&gt;mutable&lt;&#x2F;em&gt; memory space for their
internal uses. Most people do not use it for anything because in general it
should not be used unless you know exactly what you are doing (in my case, a bad
carpenter could count cases when I needed it, on single hand). In general it&#x27;s
&lt;em&gt;here be dragons&lt;&#x2F;em&gt; area.&lt;&#x2F;p&gt;
&lt;p&gt;How it&#x27;s relevant to us?&lt;&#x2F;p&gt;
&lt;p&gt;Well, OTP internally uses process dictionary (&lt;code&gt;pdict&lt;&#x2F;code&gt; for short) to store
metadata about given process that can be later used for debugging purposes. Some
data that it store are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Initial function that was run by the given process&lt;&#x2F;li&gt;
&lt;li&gt;PIDs to all ancestors of the given process&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Different processes abstractions (like &lt;code&gt;gen_server&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;GenServer&lt;&#x2F;code&gt;, Elixir&#x27;s
&lt;code&gt;Task&lt;&#x2F;code&gt;, etc.) can store even more metadata there, &lt;code&gt;logger&lt;&#x2F;code&gt; store process
metadata in process dictionary, &lt;code&gt;rand&lt;&#x2F;code&gt; store state of the PRNGs in the process
dictionary. It is used quite extensively by some OTP features.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;well-behaved-otp-process&quot;&gt;&quot;Well behaved&quot; OTP process&lt;a class=&quot;zola-anchor&quot; href=&quot;#well-behaved-otp-process&quot; aria-label=&quot;Anchor link for: well-behaved-otp-process&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;In addition to the above metadata if the process is meant to be &quot;well behaved&quot;
process in OTP system, i.e. process that can be observed and debugged using OTP
facilities, it must respond to some additional messages defined by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;sys.html&quot;&gt;&lt;code&gt;sys&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
module. Without that the features like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;observer.html&quot;&gt;&lt;code&gt;observer&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; would not be able to &quot;see&quot;
the content of the process state.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;process-memory-usage&quot;&gt;Process memory usage&lt;a class=&quot;zola-anchor&quot; href=&quot;#process-memory-usage&quot; aria-label=&quot;Anchor link for: process-memory-usage&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;As we have seen above, the &lt;code&gt;Task.async&#x2F;1&lt;&#x2F;code&gt; function form Elixir &lt;strong&gt;must&lt;&#x2F;strong&gt; do
much more than just simple &quot;start process and live with it&quot;. That was one of the
most important problems with the original process, it was using system, that was
allocating quite substantial memory alongside of the process itself, just to
operate this process. In general, that would be desirable approach (as you
&lt;strong&gt;really, really, want the debugging facilities&lt;&#x2F;strong&gt;), but in synthetic benchmarks,
it reduce the feasibility of such benchmark.&lt;&#x2F;p&gt;
&lt;p&gt;If we want to avoid that additional memory overhead in our spawned processes we
need to go back to more primitive functions in Erlang, namely &lt;code&gt;erlang:spawn&#x2F;1&lt;&#x2F;code&gt;
(&lt;code&gt;Kernel.spawn&#x2F;1&lt;&#x2F;code&gt; in Elixir). But that mean that we cannot use
&lt;code&gt;Task.await_many&#x2F;2&lt;&#x2F;code&gt; anymore, so we need to work around it by using custom
function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Monitor is internal feature of Erlang that will inform you (by sending&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # message) when process you monitor die. The returned value is type called&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # &amp;quot;reference&amp;quot; which is just simply unique value returned by the VM.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # If the process is already dead, then message will be delivered&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # immediately.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ref &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;monitor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    receive do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;DOWN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; ^ref&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await_many&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pids&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Enum&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;each&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pids&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;await&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tasks &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt;num_tasks &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # `Kernel` module is imported by default, so no need for `Kernel.` prefix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    spawn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;fn -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;      :timer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await_many&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We already removed one problem (well, two in fact, but we will go into
details in next section).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;all-your-lists-are-belongs-to-us-now&quot;&gt;All your lists are belongs to us now&lt;a class=&quot;zola-anchor&quot; href=&quot;#all-your-lists-are-belongs-to-us-now&quot; aria-label=&quot;Anchor link for: all-your-lists-are-belongs-to-us-now&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Erlang, like most of the functional programming languages, have 2 built-in
sequence types:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Tuples - which are non-growable product type of the values, so you can access
any field quite fast, but adding more values is performance no-no&lt;&#x2F;li&gt;
&lt;li&gt;(Singly) linked lists - growable type. In most case it will have single type
values in it, but in Erlang that is not always the case. It is fast to
prepend or pop data from the beginning, but do not try to do anything else if
you care about performance.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In this case we will focus on the 2nd one, as these tuples aren&#x27;t important at
all.&lt;&#x2F;p&gt;
&lt;p&gt;Singly linked list is simple data structure. It&#x27;s either special value &lt;code&gt;[]&lt;&#x2F;code&gt;
(an empty list) or it&#x27;s something called &quot;cons-cell&quot;. Cons-cells are also
simple structures - it&#x27;s 2-ary tuple (tuple with 2 elements) where first value
is head - the value in the list cell, and another one is the &quot;tail&quot; of the list (aka
rest of the list). In Elixir the cons-cell is denoted like that &lt;code&gt;[head | tail]&lt;&#x2F;code&gt;.
Super simple structure as you can see, and perfect for the functional
programming as you can add new values to the list without modifying existing
values, so you can be immutable and fast. However, if you need to construct the
sequence of a lot of values (like our list of all tasks) then we have problem.
Because Elixir promises that list returned from the &lt;code&gt;for&lt;&#x2F;code&gt; will be &lt;strong&gt;in-order&lt;&#x2F;strong&gt;
of the values passed to it. That mean that we either need to process our data
like that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;([],&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;([&lt;&#x2F;span&gt;&lt;span&gt;head &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;.(&lt;&#x2F;span&gt;&lt;span&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Where we build call stack (as we cannot have tail call optimisation there, of
course sans compiler optimisations). Or we need to build our list in reverse
order, and then reverse it before returning (so we can have TCO):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; do_map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;([],&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; agg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt; :lists&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reverse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;agg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;([&lt;&#x2F;span&gt;&lt;span&gt;head &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; agg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;.(&lt;&#x2F;span&gt;&lt;span&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span&gt; agg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which one of these approaches is more performant is irrelevant&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#erlang-perf&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
What is relevant is that we need either build call stack or construct our list
&lt;em&gt;twice&lt;&#x2F;em&gt; to be able to conform to the Elixir promises. Even if in this case we do
not care about order of the list returned by the &lt;code&gt;for&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;erlang-perf&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Sometimes body recursion will be faster, sometimes TCO will be
faster. It is impossible to tell without more benchmarking. For more info check
out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ferd.ca&#x2F;erlang-s-tail-recursion-is-not-a-silver-bullet.html&quot;&gt;superb article by Ferd Herbert&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Of course we could mitigate our problem by using &lt;code&gt;Enum.reduce&#x2F;3&lt;&#x2F;code&gt; function (or
writing it on our own) and end with code like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ref &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;monitor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    receive do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;DOWN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; ^ref&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await_many&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pids&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Enum&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;each&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pids&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;await&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tasks &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;  Enum&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reduce&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [],&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; agg &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # `Kernel` module is imported by default, so no need for `Kernel.` prefix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pid &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;      spawn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;fn -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt; :timer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;span&gt;pid &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; agg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await_many&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even then we build list of all PIDs.&lt;&#x2F;p&gt;
&lt;p&gt;Here I can also go back to the &quot;second problem* I have mentioned above.
&lt;code&gt;Task.await_many&#x2F;1&lt;&#x2F;code&gt; &lt;em&gt;also construct a list&lt;&#x2F;em&gt;. It is list of return value from all
the processes in the list. So not only we constructed list for the tasks&#x27; PIDs,
we also constructed list of return values (which will be &lt;code&gt;:ok&lt;&#x2F;code&gt; for all processes
as it&#x27;s what &lt;code&gt;:timer.sleep&#x2F;1&lt;&#x2F;code&gt; returns), and immediately discarded all of that.&lt;&#x2F;p&gt;
&lt;p&gt;How we can better? See that &lt;strong&gt;all&lt;&#x2F;strong&gt; we care is that all &lt;code&gt;num_task&lt;&#x2F;code&gt; processes
have gone down. We do not care about any of the return values, all what we want
is to know that all processes that we started went down. For that we can just
send messages from the spawned processes and count the received messages count:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;parent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;    :timer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    send&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;parent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    this &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    spawn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;fn -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    receive do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we do not have any lists involved and we still do what the original task
meant to do - spawn &lt;code&gt;num_tasks&lt;&#x2F;code&gt; processes and wait till all go down.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arguments-copying&quot;&gt;Arguments copying&lt;a class=&quot;zola-anchor&quot; href=&quot;#arguments-copying&quot; aria-label=&quot;Anchor link for: arguments-copying&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;One another thing that we can account there - lambda context and data passing
between processes.&lt;&#x2F;p&gt;
&lt;p&gt;You see, we need to pass &lt;code&gt;this&lt;&#x2F;code&gt; (which is PID of the parent) to our newly
spawned process. That is suboptimal, as we are looking for the way to reduce
amount of the memory (and ignore all other metrics at the same time). As Erlang
processes are meant to be &quot;share nothing&quot; type of processes there is problem -
we need to copy that PID to all processes. It is just 1 word (which mean 8 bytes
on 64-bit architectures, 4 bytes on 32-bit), but hey, we are microbenchmarking,
so we cut whatever we can (with 1M processes, this adds up to 8 MiBs).&lt;&#x2F;p&gt;
&lt;p&gt;Hey, we can avoid that by using yet another feature of Erlang, called
&lt;em&gt;registry&lt;&#x2F;em&gt;. This is yet another simple feature that allows us to assign PID of
the process to the atom, which allows us then to send messages to that process
using just name, we have given. While atoms are also 1 word that wouldn&#x27;t make
sense to send it as well, but instead we can do what any reasonable
microbenchmarker would do - &lt;em&gt;hardcode stuff&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;    :timer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    send&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;parent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    spawn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;fn -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    receive do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;register&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;parent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we do not pass any arguments, and instead rely on the registry to dispatch
our messages to respective processes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-more-thing&quot;&gt;One more thing&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-more-thing&quot; aria-label=&quot;Anchor link for: one-more-thing&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;As you may have already noticed we are passing lambda to the &lt;code&gt;spawn&#x2F;1&lt;&#x2F;code&gt;. That is
also suboptimal, because of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.erlang.org&#x2F;doc&#x2F;reference_manual&#x2F;code_loading.html#code-replacement&quot;&gt;difference between remote and local
call&lt;&#x2F;a&gt;. This mean that we are paying slight memory cost for
these processes to keep the old module in memory. Instead, we can use either
fully qualified function capture or &lt;code&gt;spawn&#x2F;3&lt;&#x2F;code&gt; function that accepts MFA (module,
function name, arguments list) argument. We end with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;    :timer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    send&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;parent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    spawn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;__MODULE__&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    receive do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;register&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;parent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Bench&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;num_tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;results&quot;&gt;Results&lt;a class=&quot;zola-anchor&quot; href=&quot;#results&quot; aria-label=&quot;Anchor link for: results&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;With given Erlang compilation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Erlang&#x2F;OTP 25 [erts-13.2.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Elixir 1.14.5 (compiled with Erlang&#x2F;OTP 25)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note no JIT as Nix on macOS currently&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#currently&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; disable it and I didn&#x27;t
bother to enable it in the derivation (it was disabled because there were some
issues, but IIRC these are resolved now).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;currently&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Nixpkgs rev &lt;code&gt;bc3ec5ea&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The results are as follows (in bytes of peak memory footprint returned by
&lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;time&lt;&#x2F;code&gt; on macOS):&lt;&#x2F;p&gt;
&lt;div class=&quot;table&quot;&gt;
  &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Implementation&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;1k&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;100k&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;1M&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Original&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;45047808&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;452837376&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;4227715072&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Spawn&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;43728896&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;318230528&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2869723136&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Reduce&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;43552768&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;314798080&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2849304576&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Count&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;43732992&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;313507840&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2780540928&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Registry&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;44453888&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;311988224&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2787237888&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RemoteCall&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;43597824&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;310595584&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2771525632&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;As we can see we have reduced the memory use by about 30% by just changing
from &lt;code&gt;Task.async&#x2F;1&lt;&#x2F;code&gt; to &lt;code&gt;spawn&#x2F;1&lt;&#x2F;code&gt;. Further optimisations reduced memory usage
slightly, but with no such drastic changes.&lt;&#x2F;p&gt;
&lt;p&gt;Can we do better?&lt;&#x2F;p&gt;
&lt;p&gt;Well, with some VM flags tinkering - of course.&lt;&#x2F;p&gt;
&lt;p&gt;You see, by default Erlang VM will not only create some data required for
handling process itself&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#word&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;:&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;word&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Again, word here mean 8 bytes on 64-bit and 4 bytes on 32-bit architectures.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;blockquote&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Data Type&lt;&#x2F;th&gt;&lt;th&gt;Memory Size&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Erlang process&lt;&#x2F;td&gt;&lt;td&gt;338 words when spawned, including a heap of 233 words.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;-- &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;efficiency_guide&#x2F;advanced.html#Advanced&quot;&gt;Erlang Efficiency Guide: 11. Advanced&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;As we can see, there are 105 words that are required and 233 words which are
used for preallocated heap. But this is microbenchmarking, so as we do not need
that much of memory (because our processes basically does nothing), we can
reduce it. We do not care about time performance anyway. For that we can use
&lt;code&gt;+hms&lt;&#x2F;code&gt; flag and set it to some small value, for example &lt;code&gt;1&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In addition to heap size Erlang by default load some additional data from the
BEAM files. That data is used for debugging and error reporting, but again, we
are microbenchmarking, and who need debugging support anyway (answer: everyone,
so &lt;strong&gt;do not&lt;&#x2F;strong&gt; do it in production). Luckily for us, the VM has yet another flag
for that purpose &lt;code&gt;+L&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Erlang also uses some &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;ets.html&quot;&gt;ETS&lt;&#x2F;a&gt; (Erlang Term Storage) tables by default (for
example to support process registry we have mentioned above). ETS tables can be
compressed, but by default it&#x27;s not done, as it can slow down some kinds of
operations on such tables. Fortunately there is, another, flag &lt;code&gt;+ec&lt;&#x2F;code&gt; that has
description:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Forces option compressed on all ETS tables. Only intended for test and
evaluation.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sounds good enough for me.&lt;&#x2F;p&gt;
&lt;p&gt;With all these flags enabled we get peak memory footprint at 996257792 bytes.&lt;&#x2F;p&gt;
&lt;p&gt;Compare it in more human readable units.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;Peak Memory Footprint for 1M processes&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Original code&lt;&#x2F;td&gt;&lt;td&gt;3.94 GiB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Improved code&lt;&#x2F;td&gt;&lt;td&gt;2.58 GiB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Improved code with flags&lt;&#x2F;td&gt;&lt;td&gt;0.93 GiB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Result - about 76% of the peak memory usage reduction. Not bad.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;First of all:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Please, do not use ChatGPT for writing code for microbenchmarks.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The thing about &lt;em&gt;micro&lt;&#x2F;em&gt;benchmarking is that we write code that does as little as
possible to show (mostly) meaningless features of the given technology in
abstract environment. ChatGPT cannot do that, not out of malice or incompetence,
but because it used (mostly) &lt;em&gt;good&lt;&#x2F;em&gt; and idiomatic code to teach itself,
microbenchmarks rarely are something that people will consider to have these
qualities. It also cannot consider other features that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Wetware_(brain)&quot;&gt;wetware&lt;&#x2F;a&gt; can take into
account (like our &quot;we do not need lists there&quot; thing).&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Who Watches Watchmen? - Part 1</title>
      <published>2022-01-17T00:00:00+00:00</published>
      <updated>2022-01-17T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/who-watches-watchmen-i/" type="text/html"/>
      <id>https://hauleth.dev/post/who-watches-watchmen-i/</id><summary>A lot of application use systems like Kubernetes for their deployment. In my
humble opinion it is often overkill as system, that offers most of the stuff such
thing provide, is already present in your OS. In this article I will try to
present how to utilise the most popular system supervisor from Elixir
applications.
</summary><content type="html">&lt;p&gt;I gave talk about this topic on CODE Beam V Americas, but I wasn&#x27;t really
satisfied with it. In this post I will try to describe what my presentation was
meant to be about.&lt;&#x2F;p&gt;
&lt;p&gt;If you are wondering about the presentation, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;hauleth&#x2F;who-supervises-supervisors&quot;&gt;the slides are on SpeakerDeck&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;abstract&quot;&gt;Abstract&lt;a class=&quot;zola-anchor&quot; href=&quot;#abstract&quot; aria-label=&quot;Anchor link for: abstract&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Most of the operating systems are multi-process and multi-user operating
systems. This has a lot of positive aspects. Like to be able to do more than one
thing at the time at our devices, but it introduces a lot of complexities that
in most cases are hidden from the users and developers. These things still need
to be handled in one or another way. The most basic problems are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Some processes need to be started before user can interact with the OS
in meaningful (for them) way (for example mounting filesystems, logging,
etc.)&lt;&#x2F;li&gt;
&lt;li&gt;Some processes require strict startup ordering, for example you may need
logging to be started before starting HTTP server&lt;&#x2F;li&gt;
&lt;li&gt;System operator somehow need to know when the process is ready to do their
work, which is often some time after process start&lt;&#x2F;li&gt;
&lt;li&gt;System operator should be able to check process state in case when debugging
is needed, most commonly via logs&lt;&#x2F;li&gt;
&lt;li&gt;Shutdown of the processes should be handled in a way, that will allow other
processes to be shut down cleanly (for example application that uses DB should
be down before DB itself)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;why-we-need-system-supervisor&quot;&gt;Why we need system supervisor?&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-we-need-system-supervisor&quot; aria-label=&quot;Anchor link for: why-we-need-system-supervisor&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;System supervisor is a process started early in the OS boot, that should handle
starting and managing all other processes that will be run on our system. It is
often the init process (first process started by the OS that is running with PID
1) or it is first (and sometimes only) process started by the init process.
Popular examples of such supervisors (often integrated with init systems):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;SysV which is &quot;traditional&quot; implementation that originates at UNIX System
V (hence the name)&lt;&#x2F;li&gt;
&lt;li&gt;BSD init that with some variations is used in BSD-based OSes (NetBSD,
FreeBSD), it shares some similarities to SysV init and services description is
provided by shell scripts&lt;&#x2F;li&gt;
&lt;li&gt;OpenRC that also uses shell-based scripts for service description, used by
Linux distributions like Gentoo or Alpine&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;launchd&lt;&#x2F;code&gt; that is used on Darwin (macOS, iPadOS, iOS, watchOS) systems that uses
XML-based &lt;code&gt;plists&lt;&#x2F;code&gt; for services description&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;runit&lt;&#x2F;code&gt; which is small init and supervisor, but quite capable, for example
used by Void Linux&lt;&#x2F;li&gt;
&lt;li&gt;Upstart created by Canonical Ltd. as a replacement for SysV-like init system
in Ubuntu (no longer in use in Ubuntu), still used in some distributions like
ChromeOS or Synology NAS&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;systemd&lt;&#x2F;code&gt; (this is the name, not &quot;SystemD&quot;) that was created by Red Hat
employee, (in)famous Lennart Poettering, and later was adopted by almost all
major Linux distributions which spawned some heated discussion about it&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In this article I will focus on systemd, and its approach to &quot;new-style system
daemons&quot;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Each of the solutions mentioned above has its strong and weak points. I do not
want to start another flame war whether it is good or not. It has some good in
it, and it has some bad in it. We can say that it &quot;won&quot; over the most used
distributions, and despite our love or hate towards it, we need to learn how to
live with that.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;why-systemd&quot;&gt;Why &lt;code&gt;systemd&lt;&#x2F;code&gt;?&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-systemd&quot; aria-label=&quot;Anchor link for: why-systemd&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;systemd&lt;&#x2F;code&gt; became a thing because SysV approach to ordering services&#x27; start-up was
mildly irritating and non-parallelizable. In short, SysV is starting processes
exactly in lexicographical order of files in given directory. This meant, that
even if your service didn&#x27;t need the DB at all, but it somehow ended further in
the directory listing, you ended in waiting for the DB start-up. Additionally,
SysV wasn&#x27;t really monitoring services, it just assumed that when process forked
itself to the background, then it is &quot;done&quot; with the startup, and we can
continue. This is obviously not true in many cases, for example, if your
previous shutdown wasn&#x27;t clean because of power shortage or other issue, then
your DB probably need a bit of time to rebuild state from journal. This causes
even more slowdown for the processes further in the list. This is highly
undesired in modern, cloud-based, environment, where you can often start the
machines on-demand during autoscaling actions. When there is a spike in the
traffic that need autoscaling, then the sooner new machine is in usable state
the sooner it can take load from other machines.&lt;&#x2F;p&gt;
&lt;p&gt;Different tools take different approach to solve that issue there. &lt;code&gt;systemd&lt;&#x2F;code&gt;
take approach that is derived from &lt;code&gt;launchd&lt;&#x2F;code&gt; - do not do stuff, that is not
needed. We can trigger on action of other services (obviously), but also on
stuff like socket activity, path creation&#x2F;modification, mounts, connection or
disconnection of device, time events, etc.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;DIGRESSION&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is exactly the reason why &lt;code&gt;systemd&lt;&#x2F;code&gt; has its infamous &quot;feature creep&quot;, it
doesn&#x27;t &quot;digest&quot; all services like Cron or &lt;code&gt;udev&lt;&#x2F;code&gt;. It is not that these are
&quot;tightly&quot; intertwined into &lt;code&gt;systemd&lt;&#x2F;code&gt;. You can still replace them with their
older counterparts, you will just lose all the features these bring with them.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Such lazy approach sometimes require changes into the service itself. For
example, to let supervisor know, that you are ready (not just started), you need
some way to communicate with supervisor. In &lt;code&gt;systemd&lt;&#x2F;code&gt; you can do so via UNIX
socket pointed by &lt;code&gt;NOTIFY_SOCKET&lt;&#x2F;code&gt; environment variable passed to your
application. With the same socket you can implement another useful feature
- watchdog&#x2F;heartbeat process. This mean that if for any reason your process
became non-responsive (but it will refuse to die), then supervisor will
forcefully bring process down and restart it, assuming that the error was
accidental.&lt;&#x2F;p&gt;
&lt;p&gt;About restarting, we can define behaviour of service after main process die. It
can be restarted regardless of the exit code, it can be restarted on abnormal
exit, it can remain shut, etc. Does this ring a bell? This works similarly to
OTP supervisors, but &quot;one level above&quot;. If your service utilize system
supervisor right, you can make your application almost ultimately self-healing
(by restarts).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basic-setup&quot;&gt;Basic setup&lt;a class=&quot;zola-anchor&quot; href=&quot;#basic-setup&quot; aria-label=&quot;Anchor link for: basic-setup&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now, when we know a little about how and why &lt;code&gt;systemd&lt;&#x2F;code&gt; works as it works, we
now can go to details on how to utilize that with services in Elixir.&lt;&#x2F;p&gt;
&lt;p&gt;As a base we will implement super simple Plug application:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# hello&#x2F;application.ex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    children &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span&gt;scheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;()},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Drainer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; refs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Supervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start_link&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;children&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;one_for_one&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;to_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get_env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;4000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# hello&#x2F;router.ex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  plug &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;match&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  plug &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;dispatch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  get &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    send_resp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;conn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Hello World!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I will also assume that we are using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;mix&#x2F;Mix.Tasks.Release.html&quot;&gt;Mix release&lt;&#x2F;a&gt; named &lt;code&gt;hello&lt;&#x2F;code&gt;
that we later copy to &lt;code&gt;&#x2F;opt&#x2F;hello&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;systemd-unit-file&quot;&gt;systemd unit file&lt;a class=&quot;zola-anchor&quot; href=&quot;#systemd-unit-file&quot; aria-label=&quot;Anchor link for: systemd-unit-file&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;We have only one thing left, we need to define our &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd.service.html#&quot;&gt;&lt;code&gt;hello.service&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you can create file with that content in
&lt;code&gt;&#x2F;usr&#x2F;local&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;hello.service&lt;&#x2F;code&gt; and then start it with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl start hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the simplest service imaginable, however from the start we have few
issues there:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It will run service as user running supervisor, so if it is run using global
supervisor, then it will run as &lt;code&gt;root&lt;&#x2F;code&gt;. You do not want to run anything as
&lt;code&gt;root&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;On error it will produce (BEAM) core dump, which may contain sensitive data.&lt;&#x2F;li&gt;
&lt;li&gt;It can read (and, due to being run as &lt;code&gt;root&lt;&#x2F;code&gt;, write) everything in the system,
like private data of other processes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;service-readiness&quot;&gt;Service readiness&lt;a class=&quot;zola-anchor&quot; href=&quot;#service-readiness&quot; aria-label=&quot;Anchor link for: service-readiness&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Erlang VM isn&#x27;t really the best tool out there wrt the startup times. In
addition to that our application may need some preparation steps before it can
be marked as &quot;ready&quot;. This is problem that I sometimes encounter in Docker,
where some containers do not really have any health check, and then I need to
have loop with check in some of the containers that depend on another one. This
&quot;workaround&quot; is frustrating, error prone, and can cause nasty Heisenbugs when
the timing will be wrong.&lt;&#x2F;p&gt;
&lt;p&gt;Two possible solutions for this problem are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Readiness probe - another program that is ran after the main process is
started, that checks whether our application is ready to work.&lt;&#x2F;li&gt;
&lt;li&gt;Notification system where our application uses some common protocol to inform
the supervisor that it finished setup and is ready for work.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;systemd supports the second approach via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;sd_notify.html&quot;&gt;&lt;code&gt;sd_notify&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. The approach
there is simple - we have &lt;code&gt;NOTIFY_SOCKET&lt;&#x2F;code&gt; environment variable that contain path
to the Unix datagram socket, that we can use to send information about state of
our application. This socket accept set of different messages, but right now,
for our purposes, we will focus only on few of them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;READY=1&lt;&#x2F;code&gt; - marks our service as ready, aka it is ready to do its work (for
example accept incoming HTTP connections in our example). It need to be sent
within given timespan after start of the VM, otherwise the process will be
killed and possibly restarted&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;STATUS=name&lt;&#x2F;code&gt; - sets status of our application that can be checked via
&lt;code&gt;systemctl status hello.service&lt;&#x2F;code&gt;, this allows us to have better insight into
what is the high level state without manually traversing through logs&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;RELOADING=1&lt;&#x2F;code&gt; - marks, that our application is reloading, which in general may
mean a lot of things, but there it will be used to mark &lt;code&gt;:init.restart&#x2F;0&lt;&#x2F;code&gt;-like
behaviour (due to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlang&#x2F;otp&#x2F;issues&#x2F;4698&quot;&gt;erlang&#x2F;otp#4698&lt;&#x2F;a&gt; there is wrapper for that function in
&lt;code&gt;systemd&lt;&#x2F;code&gt; library). The process need then to send &lt;code&gt;READY=1&lt;&#x2F;code&gt; within given
timespan, or the process will be marked as a malfunctioning, and will be
forcefully killed and possibly restarted&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;STOPPING=1&lt;&#x2F;code&gt; - marks, that our application began shutting down process, and
will be closing soon. If the process will not close within given timespan, it
will be forcefully killed&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These messages provide us enough power to not only mark the service as ready,
but also provides additional information about system state. So even operator,
who knows a little about Erlang or our application runtime, will be able to
understand what is going on.&lt;&#x2F;p&gt;
&lt;p&gt;The main thing is that systemd will wait with activation of the dependents of
our system as well as the &lt;code&gt;systemctl start&lt;&#x2F;code&gt; and &lt;code&gt;systemctl restart&lt;&#x2F;code&gt; commands
will wait until our service declare that it is ready.&lt;&#x2F;p&gt;
&lt;p&gt;Usage of such feature is quite simple:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Define `Type=` to `notify`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;notify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;WatchdogSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;1min&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then in our supervisor tree we need to add &lt;code&gt;:systemd.ready()&lt;&#x2F;code&gt; &lt;strong&gt;after&lt;&#x2F;strong&gt; last
process needed for proper functioning of our application, in our simple example
it is after &lt;code&gt;Plug.Cowboy&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# hello&#x2F;application.ex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    children &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span&gt;scheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;()},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;      :systemd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ready&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; # &amp;lt;-- it is function call, as it returns proper&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                        # `child_spec&#x2F;0`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Drainer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; refs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Supervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start_link&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;children&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;one_for_one&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;to_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get_env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;4000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now restarting our service will not finish immediately, but will wait until our
service will declare that it is ready.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl restart hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;About &lt;code&gt;STOPPING=1&lt;&#x2F;code&gt; - the magic thing is that the &lt;code&gt;systemd&lt;&#x2F;code&gt; library takes care of
it for you. As soon as the system will be scheduled to shutdown this message
will be automatically sent, and the operator will be notified about this fact.&lt;&#x2F;p&gt;
&lt;p&gt;We can also provide more information about state of our application. As you may
have already noticed, we have &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;plug_cowboy&#x2F;2.5.2&#x2F;Plug.Cowboy.Drainer.html&quot;&gt;&lt;code&gt;Plug.Cowboy.Drainer&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; there. It is process that
will delay shutdown of our application while there are still open connections.
This can take some time, so it would be handy if the operator would see that the
draining is in progress. We can easily achieve that by again changing our
supervision tree to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# hello&#x2F;application.ex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    children &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span&gt;scheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;()},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;      :systemd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ready&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;      :systemd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set_status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;down&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;span&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;drained&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Drainer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; refs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; shutdown&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10_000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;      :systemd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set_status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;down&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;span&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;draining&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Supervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;start_link&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;children&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;one_for_one&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cowboy_opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;to_integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get_env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;4000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now when we will shutdown our application by:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# systemctl stop hello.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we have some connections open to our service (you can simulate that with
&lt;code&gt;wrk&lt;&#x2F;code&gt;) then when we ran &lt;code&gt;systemctl status hello.service&lt;&#x2F;code&gt; in separate terminal
(previous will be blocked until our service shuts down) then you will be able to
see something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;● hello.service - Example Plug application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Loaded: loaded (&#x2F;usr&#x2F;local&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;hello.service; static; vendor preset: enabled)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Active: deactivating (stop-sigterm) since Sat 2022-01-15 17:46:30 CET;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          1s ago&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Main PID: 1327 (beam.smp)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Status: &amp;quot;draining&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Tasks: 19 (limit: 1136)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Memory: 106.5M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can notice that the &lt;code&gt;Status&lt;&#x2F;code&gt; is set to &lt;code&gt;&quot;draining&quot;&lt;&#x2F;code&gt;. As soon as all
connections will be drained it will change to &lt;code&gt;&quot;drained&quot;&lt;&#x2F;code&gt; and then the
application will shut down and service will be marked as &lt;code&gt;inactive&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;watchdog&quot;&gt;Watchdog&lt;a class=&quot;zola-anchor&quot; href=&quot;#watchdog&quot; aria-label=&quot;Anchor link for: watchdog&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Watchdog allows us to monitor our application for responsiveness (as mentioned
above). It is simple feature that requires our application to ping systemd
within specified interval, otherwise the application will be forcibly shut down
as malfunctioning. Fortunately for us, the &lt;code&gt;systemd&lt;&#x2F;code&gt; library that provides our
integration, have that feature out of the box, so all we need to do to achieve
expected result is set &lt;code&gt;WatchdogSec=&lt;&#x2F;code&gt; option in our &lt;code&gt;systemd.service&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;notify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;WatchdogSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;1min&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This configuration says that if the VM will not send healthy message each 1
minute interval, then the service will be marked as malfunctioning. From the
application side we can manage state of the watchdog in several ways:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;By setting &lt;code&gt;systemd.watchdog_check&lt;&#x2F;code&gt; configuration option we can configure the
function that will be called on each check. If that function return &lt;code&gt;true&lt;&#x2F;code&gt;
then it mean that application is healthy and the systemd should be notified
with ping, if it returns &lt;code&gt;false&lt;&#x2F;code&gt; or fail, then the check will be omitted.&lt;&#x2F;li&gt;
&lt;li&gt;Manually sending trigger message in case of detected problems via
&lt;code&gt;:systemd.watchdog(trigger)&lt;&#x2F;code&gt;, it will immediately mark service as
malfunctioning and will trigger action defined in service unit file (by
default it will restart application)&lt;&#x2F;li&gt;
&lt;li&gt;Disabling built-in watchdog process via &lt;code&gt;:systemd.watchdog(:disable)&lt;&#x2F;code&gt; and then
manually sending &lt;code&gt;:systemd.watchdog(:ping)&lt;&#x2F;code&gt; within expected intervals
(discouraged)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;security&quot;&gt;Security&lt;a class=&quot;zola-anchor&quot; href=&quot;#security&quot; aria-label=&quot;Anchor link for: security&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;We should start with changing default user and group which is assigned to our
process. We can do so in 2 different ways:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use some existing user and group by defining &lt;code&gt;User=&lt;&#x2F;code&gt; and &lt;code&gt;Group=&lt;&#x2F;code&gt; directives
in our service definition; or&lt;&#x2F;li&gt;
&lt;li&gt;Create ephemeral user on-demand before our service starts, by using directive
&lt;code&gt;DynamicUser=true&lt;&#x2F;code&gt; in service definition.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I prefer second option, as it additionally provides a lot of other security
related options, like creating private &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; directory, making system
read-only, etc. This has also some disadvantages, like removing all of given
data on service shutdown, however there are options to keep some data between
launches.&lt;&#x2F;p&gt;
&lt;p&gt;In addition to that we can add &lt;code&gt;PrivateDevices=true&lt;&#x2F;code&gt; that will hide all
physical devices from &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; leaving only pseudo devices like &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; or
&lt;code&gt;&#x2F;dev&#x2F;urandom&lt;&#x2F;code&gt; (so you will be able to use &lt;code&gt;:crypto&lt;&#x2F;code&gt; and &lt;code&gt;:ssl&lt;&#x2F;code&gt; modules without
problems).&lt;&#x2F;p&gt;
&lt;p&gt;Next thing is that we can do, is to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlef.github.io&#x2F;security-wg&#x2F;secure_coding_and_deployment_hardening&#x2F;crash_dumps&quot;&gt;disable crash dumps generated by BEAM&lt;&#x2F;a&gt;.
While not strictly needed in this case, it is worth remembering, that it isn&#x27;t
hard to achieve, just use &lt;code&gt;Environment=ERL_CRASH_DUMP_SECONDS=0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Our new, more secure, &lt;code&gt;hello.service&lt;&#x2F;code&gt; will look like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Hello World service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Requires&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;network.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;notify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;opt&#x2F;hello&#x2F;bin&#x2F;hello start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;WatchdogSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;1min&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# We need to add capability to be able to bind on port 80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;CapabilityBoundingSet&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;CAP_NET_BIND_SERVICE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Hardening&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;PrivateDevices&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ERL_CRASH_DUMP_SECONDS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem with that configuration is that our service is now capable on
binding &lt;strong&gt;any&lt;&#x2F;strong&gt; port under 1024. For example, if there is some security issue,
then the malicious party can open any of the restricted ports and then serve
whatever data they want there. This can be quite problematic, and the solution
for that problem will be covered in Part 2, where we will cover socket passing
and socket activation for our service.&lt;&#x2F;p&gt;
&lt;p&gt;With that we achieved quite basic level of isolation to what Docker (or other
container runtime) is providing, but it do not require &lt;code&gt;overlayfs&lt;&#x2F;code&gt; or anything
more, than what you already have on your machine. That means, updates done by
your system package manager will be applied to all running services. With that
you do not need to rebuild all your containers when there is security patch
issued for any of your dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;Of course it only scratches the surface of what is possible with systemd wrt
the hardening of the services. More information can be found in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.redhat.com&#x2F;sysadmin&#x2F;mastering-systemd&quot;&gt;RedHat
article&lt;&#x2F;a&gt; and in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd-analyze.html#systemd-analyze%20security%20%5BUNIT...%5D&quot;&gt;&lt;code&gt;systemd-analyze security&lt;&#x2F;code&gt; command
output&lt;&#x2F;a&gt;. Possible features are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Creation of the private networks for your services&lt;&#x2F;li&gt;
&lt;li&gt;Disallowing creation of socket connections that are outside of the specified
set of families&lt;&#x2F;li&gt;
&lt;li&gt;Make only some paths readable&lt;&#x2F;li&gt;
&lt;li&gt;Hide some paths from the process&lt;&#x2F;li&gt;
&lt;li&gt;etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Coverage of just that topic is a little bit out of scope for this blog post, so
I encourage you to read the documentation of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd.exec.html&quot;&gt;&lt;code&gt;systemd.exec&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and
articles mentioned above for more details.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This blog post is already quite lengthy, so I will split it into separate parts.
There probably will be 3 of them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;who-watches-watchmen-i&#x2F;.&#x2F;#top&quot;&gt;Part 1 - Basics, security, and FD passing (this one)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;who-watches-watchmen-ii&#x2F;&quot;&gt;Part 2 - Socket activation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Part 3 - Logging&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Log all the things</title>
      <published>2022-01-02T00:00:00+00:00</published>
      <updated>2022-01-02T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/log-all-the-things/" type="text/html"/>
      <id>https://hauleth.dev/post/log-all-the-things/</id><summary type="html"><p>In Elixir 1.11 landed set of new features that allows for more powerful logging
by utilising Erlang's <a rel="external" href="https://erlang.org/doc/man/logger.html"><code>logger</code></a> features. Here I will try to describe
new possibilities and how You can use them to improve your logs.</p></summary><content type="html">&lt;p&gt;In Elixir 1.11 landed set of new features that allows for more powerful logging
by utilising Erlang&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;logger.html&quot;&gt;&lt;code&gt;logger&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; features. Here I will try to describe
new possibilities and how You can use them to improve your logs.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;levels&quot;&gt;New log levels&lt;a class=&quot;zola-anchor&quot; href=&quot;#levels&quot; aria-label=&quot;Anchor link for: levels&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Elixir gained 4 new log levels to total 8 (from most verbose to least verbose):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;debug&lt;&#x2F;li&gt;
&lt;li&gt;info&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;notice&lt;&#x2F;strong&gt; *&lt;&#x2F;li&gt;
&lt;li&gt;warning (renamed from warn)&lt;&#x2F;li&gt;
&lt;li&gt;error&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;critical&lt;&#x2F;strong&gt; *&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;alert&lt;&#x2F;strong&gt; *&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;emergency&lt;&#x2F;strong&gt; *&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;small&gt;* new levels&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This provides finer graded verbosity control, due to compatibility reasons, in
Elixir backends we need to translate these levels back to &quot;old&quot; set of 4. The
current table looks like:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Call level&lt;&#x2F;th&gt;&lt;th&gt;What Elixir backend will see&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;debug&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;debug&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;info&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;info&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;notice&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;info&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; *&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;warning&lt;&#x2F;code&gt; (or &lt;code&gt;warn&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;warn&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;error&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;error&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;critical&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;error&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; *&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;alert&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;error&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; *&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;emergency&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;error&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; *&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;small&gt;* &quot;translated&quot; messages&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can set verbosity to all levels. This may be confusing during the transition
period, but we cannot change the behaviour until Elixir 2 (which is not
happening any time soon).&lt;&#x2F;p&gt;
&lt;p&gt;Usage of the new levels is &quot;obvious&quot;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;notice&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Will produce message with &lt;code&gt;notice&lt;&#x2F;code&gt; level of verbosity.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, the &lt;code&gt;logger.level&lt;&#x2F;code&gt; option in configuration supports 2 additional
verbosity levels that you can use in your config:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:all&lt;&#x2F;code&gt; - all messages will be logged, logically exactly the same as &lt;code&gt;:debug&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:none&lt;&#x2F;code&gt; - no messages will be logged&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;per-module-level&quot;&gt;Per module log level&lt;a class=&quot;zola-anchor&quot; href=&quot;#per-module-level&quot; aria-label=&quot;Anchor link for: per-module-level&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This is change that can be quite handy during debugging sessions. With this
change we have 4 new functions in &lt;code&gt;Logger&lt;&#x2F;code&gt; module:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;logger&#x2F;Logger.html#get_module_level&#x2F;1&quot;&gt;&lt;code&gt;get_module_level&#x2F;1&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;logger&#x2F;Logger.html#put_module_level&#x2F;2&quot;&gt;&lt;code&gt;put_module_level&#x2F;2&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;logger&#x2F;Logger.html#delete_module_level&#x2F;1&quot;&gt;&lt;code&gt;delete_module_level&#x2F;1&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;logger&#x2F;Logger.html#delete_all_module_level&#x2F;0&quot;&gt;&lt;code&gt;delete_all_module_level&#x2F;0&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These allow us to manipulate verbosity level on per-module basis. What is
non-obvious and is super handy is that it allows both lowering &lt;strong&gt;and raising&lt;&#x2F;strong&gt;
verbosity for given module. This mean that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;require&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Logger&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;configure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;level&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; run&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;I am still there&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; # Does not log anything&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Set `debug` level for `Foo` module only&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;put_module_level&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# `I am still there` is logged&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;I will not be printed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Nothing got logged as top-level verbositi is still set to `:error`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course it will not work if you decide to use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;logger&#x2F;Logger.html#module-application-configuration&quot;&gt;compile time purging&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;handlers&quot;&gt;Logger handlers&lt;a class=&quot;zola-anchor&quot; href=&quot;#handlers&quot; aria-label=&quot;Anchor link for: handlers&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Warning!&lt;&#x2F;strong&gt; This is not fully implemented in both - Erlang and Elixir. Writing
your own handlers without additional knowledge can cause overload problems.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Erlang together with their logging implementation needed to provide a way to
ingest these logs somehow. This is done via Erlang logger handlers (in this
article called &lt;em&gt;handlers&lt;&#x2F;em&gt; in contrast to Elixir backends called &lt;em&gt;backends&lt;&#x2F;em&gt;
there).&lt;&#x2F;p&gt;
&lt;p&gt;Handlers are modules that export at least 1 function &lt;code&gt;log&#x2F;2&lt;&#x2F;code&gt; that takes 2
arguments:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;log_event&lt;&#x2F;code&gt; which is a map with 3 fields:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:level&lt;&#x2F;code&gt; - verbosity level&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:msg&lt;&#x2F;code&gt; - tuple describing message:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{:io.format(), [term()]}&lt;&#x2F;code&gt; - format string and list of terms that should
be passed to &lt;code&gt;:io_lib.format&#x2F;2&lt;&#x2F;code&gt; function&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;{:report, map() | keyword()}&lt;&#x2F;code&gt; - report that can be formatted into string
by &lt;code&gt;report_cb&#x2F;{1,2}&lt;&#x2F;code&gt; set in metadata map (see below)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;{:string, :unicode.chardata()}&lt;&#x2F;code&gt; - raw string that should be printed as
a message&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:meta&lt;&#x2F;code&gt; - map containing all metadata for given event. All keys should be
atoms and values can be anything. Some keys have special meaning, and some
of them will be populated automatically by the &lt;code&gt;Logger&lt;&#x2F;code&gt; macros and functions.
These are:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:pid&lt;&#x2F;code&gt; - PID of the process that fired log event&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:gl&lt;&#x2F;code&gt; - group leader of the process that fired log event&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:mfa&lt;&#x2F;code&gt; - tuple in form of &lt;code&gt;{module(), name :: atom(), arity :: non_neg_integer()}&lt;&#x2F;code&gt;
that describe function that fired log event&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:file&lt;&#x2F;code&gt; - filename of file that defines the code that fired log event&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:line&lt;&#x2F;code&gt; - line in the given file where the log event was fired&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:domain&lt;&#x2F;code&gt; - list of atoms that can be used to describe log events
hierarchy which then can be used for filtering. All events fired using
&lt;code&gt;Logger&lt;&#x2F;code&gt; macros and functions will have &lt;code&gt;:elixir&lt;&#x2F;code&gt; prepended to their
domain list.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:report_cb&lt;&#x2F;code&gt; - function that will be used to format &lt;code&gt;{:report, map() | keyword()}&lt;&#x2F;code&gt; messages. This can be either 1-ary function, that takes report
and returns &lt;code&gt;{:io.format(), [term()]}&lt;&#x2F;code&gt; leaving truncation and further
formatting up to the main formatter, or 2-ary function that takes report
and configuration map &lt;code&gt;%{depth: pos_integer() | :unlimited, chars_limit: pos_integer() | :unlimited, single_line: boolean()}&lt;&#x2F;code&gt; and returns already
formatted &lt;code&gt;:unicode.chardata()&lt;&#x2F;code&gt;. More about it can be found in &lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;log-all-the-things&#x2F;#structured-logging&quot;&gt;separate
section&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Return value of this function is ignored. If there will be any exception raised
when calling this function, then it will be captured and failing handler will be
removed. This is important, as if such handler is the only one, then you can be
left without any logging handler and miss logs.&lt;&#x2F;p&gt;
&lt;p&gt;The important thing about Erlang handlers and Elixir backends is that Erlang
handlers functions are called &lt;strong&gt;within caller process&lt;&#x2F;strong&gt; while Elixir backends
are called in separate process. This mean that wrongly written Erlang handler
can cause quite substantial load on application.&lt;&#x2F;p&gt;
&lt;p&gt;To read on other, optional, callbacks that can be defined by Erlang handler, that
will not be covered there, I suggest looking into &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;logger.html#formatter-callback-functions&quot;&gt;Erlang documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;structured-logging&quot;&gt;Structured logging&lt;a class=&quot;zola-anchor&quot; href=&quot;#structured-logging&quot; aria-label=&quot;Anchor link for: structured-logging&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;One of the biggest new features in the Elixir 1.11 is support for structured
logging. This mean that the log message do not need to be free-form string, but
instead we can pass structure, that can provide more machine-readable data for
processing in log aggregators. In Elixir 1.11 is simple as passing map as a
first argument to the &lt;code&gt;Logger&lt;&#x2F;code&gt; macros:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;info&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;completed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  response&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will produce message that looks like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;log&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;14:08:46.849&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-inserted&quot;&gt; [info]&lt;&#x2F;span&gt;&lt;span&gt;  [response: :ok, status: :completed]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see, the map (called &lt;em&gt;report&lt;&#x2F;em&gt;) is formatted as a keyword list. This is
default way to present the report data. Unfortunately we cannot access the
metadata from the Elixir backends, but we have 2 ways to make these messages
more readable for the human operator:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Utilise &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;logger&#x2F;Logger.Translator.html&quot;&gt;&lt;code&gt;Logger&lt;&#x2F;code&gt;&#x27;s translators&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Using &lt;code&gt;:report_cb&lt;&#x2F;code&gt; field in metadata&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;1st option is described quite good in Elixir documentation and is available
since Elixir 1.0 as it was used to translate &lt;code&gt;error_logger&lt;&#x2F;code&gt; messages in old
Erlang versions. Here I will describe the 2nd option which provide way for
&lt;strong&gt;caller&lt;&#x2F;strong&gt; to define how report should be formatted into human-readable string.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;:report_cb&lt;&#x2F;code&gt; accepts 2 kind of functions as an argument:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1-ary function, that takes report as an argument and should return tuple
in form of &lt;code&gt;{:io.format(), [term()]}&lt;&#x2F;code&gt; that will be later formatted
respectively by the formatters.&lt;&#x2F;li&gt;
&lt;li&gt;2-ary function that takes report and configuration map as an arguments and
should return formatted string.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;1st option is much easier for most use cases, as it do not force you to worry
about handling width, depth, and multiline logs, as it will all be handled for
you.&lt;&#x2F;p&gt;
&lt;p&gt;For example, instead of doing:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;info&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Started HTTP server on http:&#x2F;&#x2F;localhost:8080&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can do:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;info&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8080&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;localhost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyEndpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Cowboy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  report_cb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;__MODULE__&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;report_cb&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# …&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; report_cb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;  {&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Started ~s server on ~s:&#x2F;&#x2F;~s:~B&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;, [&lt;&#x2F;span&gt;&lt;span&gt;protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;While the second entry seems much more verbose, with proper handler, it can
provide much more detailed output. Just imagine that we would have handler that
output JSON data and what information we could contain in such message:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Started HTTP server on http:&#x2F;&#x2F;localhost:8080&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;mfa&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;MyMod.start&#x2F;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo.ex&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;line&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now our log aggregation service need to parse &lt;code&gt;msg&lt;&#x2F;code&gt; field to extract all
information that is contained there, like port, address, and protocol. With
structured logging we can have that message available already there while
presenting the &quot;human readable&quot; form as well:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Started HTTP server on http:&#x2F;&#x2F;localhost:8080&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;localhost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8080&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;protocol&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;MyEndpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Plug.Cowboy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;mfa&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;MyMod.start&#x2F;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo.ex&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;line&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see there that we can have more information available in the structured
log that would otherwise needed to be crammed somewhere into the text message,
even if it is not important in &quot;regular&quot; Ops observability.&lt;&#x2F;p&gt;
&lt;p&gt;This can raise a question - why not use metadata for such functionality, like it
is available in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Nebo15&#x2F;logger_json&quot;&gt;&lt;code&gt;LoggerJSON&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hex.pm&#x2F;packages&#x2F;ink&quot;&gt;&lt;code&gt;Ink&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;? The reason is that their reason
existence is different. Metadata meant for &quot;meta&quot; stuff like location, tracing
ID, but not for the information about the message itself. It is best shown on
example. For this use Elixir&#x27;s implementation of &lt;code&gt;GenServer&lt;&#x2F;code&gt; wrapper that
produces error log entry on unknown message handled by default &lt;code&gt;handle_info&#x2F;2&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Report&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;GenServer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;no_handle_info&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      module&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; __MODULE__&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      message&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; proc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    error_logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;tag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;error_msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    report_cb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;GenServer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;format_report&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see there, the report contains information like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:label&lt;&#x2F;code&gt; - that describes type of the event&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:report&lt;&#x2F;code&gt; - content of the &quot;main&quot; event
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:module&lt;&#x2F;code&gt; - module that created the event, it is important to notice, that
it is also present in metadata (as part of &lt;code&gt;:mfa&lt;&#x2F;code&gt; key), but their meaning is
different. Module name here is meant for the operator to know the name of
the implementor that failed to handle message, while &lt;code&gt;:mfa&lt;&#x2F;code&gt; is meant to
describe the location of the code that fired the event.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:message&lt;&#x2F;code&gt; - the message itself that hasn&#x27;t been handled. Notice, that it is
not stringified in any way there, it is simply passed &quot;as is&quot; to the
report. It is meant to be stringified later by the &lt;code&gt;:report_cb&lt;&#x2F;code&gt; function.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:name&lt;&#x2F;code&gt; - name of the process. Remember, similarly to &lt;code&gt;:module&lt;&#x2F;code&gt;, the PID of
the current process is part of the metadata. So in theory we could use value
from there, but their meaning is different (additionally this one may be an
atom in case if the process is locally registered with name).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Metadata on the other hand contains information that will be useful for
filtering or formatting of the event.&lt;&#x2F;p&gt;
&lt;p&gt;The rule of thumb you can follow is:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If it is thing that you will want to filter on, then it probably should be
part of the metadata. If you want to aggregate information or just display
them, it should be part of the message report.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;log-filtering&quot;&gt;Log filtering&lt;a class=&quot;zola-anchor&quot; href=&quot;#log-filtering&quot; aria-label=&quot;Anchor link for: log-filtering&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Finally we come to first feature that is not directly accessible from the Elixir
&lt;code&gt;Logger&lt;&#x2F;code&gt; API (yet). Erlang&#x27;s &lt;code&gt;logger&lt;&#x2F;code&gt; have powerful functionality for filtering
log messages which allows us to dynamically decide which message should, or
should not be logged. These even can alter messages on the fly.&lt;&#x2F;p&gt;
&lt;p&gt;Currently that functionality is available only via &lt;code&gt;:logger&lt;&#x2F;code&gt; module. It can be
used like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; MyFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;log_event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # …&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;:logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;add_primary_filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;my_filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;:logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;add_handler_filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;handler_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;my_filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Few important things that need to be remembered when writing such filters:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Best practice is to make such functions public and define filters using
remote function capture, like &lt;code&gt;&amp;amp;__MODULE__.process_disabled&#x2F;2&lt;&#x2F;code&gt; (so not
anonymous functions either). It will make such filter much easier for VM to
handle (it is bigger topic why it is that, I may to cover it in another post).&lt;&#x2F;li&gt;
&lt;li&gt;Filters are run &lt;strong&gt;within the same process that fired log event&lt;&#x2F;strong&gt;, so it is
important to make such filters as fast as possible, and do not do any heavy
work there.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Filters can be used for 2 different things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preventing some messages from being logged&lt;&#x2F;li&gt;
&lt;li&gt;Modifying a message&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;While the former is much more common, I will try to describe both use cases
there, as the latter is also quite useful.&lt;&#x2F;p&gt;
&lt;p&gt;Filters are defined as 2-ary functions where 1st argument is log event, and
second argument is any term that can be used as a configuration for filter.
Filter should return one of these 3 values:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:stop&lt;&#x2F;code&gt; - which will immediately discard message and do not run any additional
filters.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:ignore&lt;&#x2F;code&gt; - which mean that given filter didn&#x27;t recognise the given message
and leaves it up to other filters to decide on the action. If all filters
return &lt;code&gt;:ignore&lt;&#x2F;code&gt; then &lt;code&gt;:filter_default&lt;&#x2F;code&gt; option for the handler will be taken.
By default it is &lt;code&gt;:log&lt;&#x2F;code&gt;, which mean that message will be logged, but default
handler has it set to &lt;code&gt;:stop&lt;&#x2F;code&gt; by default, which mean, that non-matching
messages will be discarded.&lt;&#x2F;li&gt;
&lt;li&gt;Just log event (possibly modified) that will cause next filter to be called
with altered message. The message returned by the last filter (or in case of
&lt;code&gt;:ignore&lt;&#x2F;code&gt; return, previous filters) will be the message passed to handler.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;preventing-some-messages-from-being-logged&quot;&gt;Preventing some messages from being logged&lt;a class=&quot;zola-anchor&quot; href=&quot;#preventing-some-messages-from-being-logged&quot; aria-label=&quot;Anchor link for: preventing-some-messages-from-being-logged&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Most common use-case for filters will probably be rejecting messages that aren&#x27;t
important for us. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;logger_filters.html&quot;&gt;Erlang even prepared some useful filters&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;domain&lt;&#x2F;code&gt; - allow filtering by metadata &lt;code&gt;:domain&lt;&#x2F;code&gt; field (remember as I said
that metadata is for filtering?). It supports multiple possible relations
between the log domain and defined domain.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;level&lt;&#x2F;code&gt; - allow filtering (in or out) messages depending on their level, in
both directions. It will allow you to filter messages with higher level for
some handlers. Just remember, that it will not receive messages that will not
pass primary&#x2F;module level.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;progress&lt;&#x2F;code&gt; - filters all reports from &lt;code&gt;supervisor&lt;&#x2F;code&gt; and
&lt;code&gt;application_controller&lt;&#x2F;code&gt;. Simply, reduces startup&#x2F;process shutdown chatter
that often is meaningless for most time.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;remote_gl&lt;&#x2F;code&gt; - filters messages coming from group leader on another node.
Useful when you want to discard&#x2F;log messages coming from other nodes in
cluster.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;modifying-a-message&quot;&gt;Modifying a message&lt;a class=&quot;zola-anchor&quot; href=&quot;#modifying-a-message&quot; aria-label=&quot;Anchor link for: modifying-a-message&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Sometimes there is need to alter messages in the system. For example, we may need
to prevent sensitive information from being logged. When using &quot;old&quot; Elixir
approach you could abuse translators, but that was error prone, as first
successful translator was breaking pipeline, so you couldn&#x27;t just smash one on
top and then keep rest working as is. With &quot;new&quot; approach and structured logging
you can just traverse the report and replace all occurrences of the unsafe data
with anonymized data. For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; filter_out_password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;event &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;filtered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;[FILTERED]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; {&lt;&#x2F;span&gt;&lt;span&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;-&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;map &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt; @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;filtered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;span&gt; into&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;{&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; {&lt;&#x2F;span&gt;&lt;span&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;-&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;map &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt; @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;filtered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;span&gt; into&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; when&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; is_list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span&gt; elem &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span&gt; list &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span&gt; elem &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt; @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;filtered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;      {&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt; {&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt; @&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-module z-elixir&quot;&gt;filtered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; {&lt;&#x2F;span&gt;&lt;span&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      other &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;other&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; replace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;other&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do: other&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This snippet will replace all occurrences of &lt;code&gt;:password&lt;&#x2F;code&gt; or &lt;code&gt;&quot;password&quot;&lt;&#x2F;code&gt; with
filtered out value.&lt;&#x2F;p&gt;
&lt;p&gt;The disadvantage of such approach - it will make all messages with such fields
allowed in case if your filter has &lt;code&gt;:filter_default&lt;&#x2F;code&gt; set to &lt;code&gt;:stop&lt;&#x2F;code&gt;. That mean,
that if you want to make some of them rejected anyway, then you will need to
manually add an additional step to reject messages that do not fit into your
patterns. Alternatively, you can use &lt;code&gt;filter_default: :log&lt;&#x2F;code&gt; and then use opt-out
logging. There currently is no way to alter the message and make other filters
decide whether log it or not (as of OTP 24).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;New features and possibilities with relation to logging in Elixir 1.11 can be
overwhelming. Fortunately, all the new features are optional and provided in
addition to &quot;good &#x27;ol &lt;code&gt;Logger.info(&quot;logging&quot;)&lt;&#x2F;code&gt;&quot;. But for the people who works on
the observability in BEAM (EEF Observability WG, Sentry, Logflare, etc.) it
brings a lot of new powerful capabilities.&lt;&#x2F;p&gt;
&lt;p&gt;I am thrilled to see what will people create using all that power.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Treachery of Representation</title>
      <published>2020-04-27T00:00:00+00:00</published>
      <updated>2020-04-27T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/treachery-of-representation/" type="text/html"/>
      <id>https://hauleth.dev/post/treachery-of-representation/</id><summary>Representation is not data - something that developers (and not only them)
often forgot when working with different data.</summary><content type="html">&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;treachery-of-images.jpg&quot; alt=&quot;Treachery of Images&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I had that discussion on different chats few times already, but it is always
troublesome for people (not just programmers):&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Representation is not data&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And this concept is confused &lt;strong&gt;a lot&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Almost any of you know that you can do &lt;code&gt;ping 1.1.1.1&lt;&#x2F;code&gt;, however did you know that
you can also do &lt;code&gt;ping 16843009&lt;&#x2F;code&gt; and the result will be the same? Magic? Not
really. What we commonly treat as an IPv4 address &lt;code&gt;1.1.1.1&lt;&#x2F;code&gt; is only textual
representation of the IPv4 which in reality is single 32-bit number which is
represented as dot separated 8-bit values just out of convenience. The same
applies to SHA-1 hashes, UUIDs, etc.&lt;&#x2F;p&gt;
&lt;p&gt;We people are good at finding patterns and simplifications, so when one sees
something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----BEGIN PGP PUBLIC KEY BLOCK-----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mQINBFd1CwMBEADTJG+QszZ9JK6G+IZpvK&#x2F;g8mJicqKVTV1OmI1toIml5c&#x2F;5r&#x2F;70&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dBc1FuASTM58PPZYJoKkbIh489QIvTm+8UdYu9zNRkT33el7pW1lEe5A6sq2bvoY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GE8DioHTewdoSDPf7KIaZQeRcIY4n93rUOwA6GEtNpyYGP6ss5Y7BGk4ltSioe7N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;o+4ZmWoQZwZzRon3t1eWVVP9tRMG5nLzL3XA5FK8TqoYuuIOR0Kw9+yK&#x2F;CIJi6EV&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NGXidQEhRX&#x2F;e6cDcqmo6LQuQluuhpwKjD3rVIq5P55kDcyUXHkcr9&#x2F;RBIY1GCw0m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;r03H053xYhPib4S3fkcGMz1zrvgPR8M6T8VYXERZDjKzQbkkjKx2umP+MQb57N&#x2F;m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ndr+vks5PoPOPTGS9DYPaWf0fTVWQz&#x2F;Wr6SuqKYWOObw2Ql1fOFS9dlQ26VHqtdP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CjCS&#x2F;+kxTWP0SNIlvmICj68JNq0Elti8DNF+8K4U&#x2F;zjqphqLUOMYo+bfxF3Xudlx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;X5tXXRd2Jx3rkquLhlOaIfwx5ZKkc0jFvFq6L6iQ8M3w2osTTQ8wzLVrKcA&#x2F;1E37&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vzFw0eLlAHxqKKx8AGXhlG+bu4z9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=HbWE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----END PGP PUBLIC KEY BLOCK-----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then they will automatically say that this is PGP public key, however it is not!
This is only armored (textual) representation of such. We can find infinite
amount of ways to represent this in different formats that will suit our needs.
We can use binary format, we can post it as huge integer:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1657454081776872747238013876359322713234391537499703933766980145269184386317049&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8330933605635736383746482612365150874768089262930090931944711968773749521913699&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7027071169368463413472374786860753667060249108643195012586135134901393013828317&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1125513524511702912188470760919764295140961468869648430645347829208242125220011&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3151968877120814976862830922750002170809783899223077039784557147675345249970781&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5464553976008128226157133495317638249211710007765696991167161819945117066390428&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3919051957061561015867974004807638646034325543036054946820462087690124141551114&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9854678368254378572150652196681912690617688434615368858186497935662439355552496&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4729580502224487557084501045154245589928832642849687361389957940229955065758222&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6366651257907657297666835432894495612402178521246832570964915000759172307812244&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6160593540459285722105074344450899751799861113519463231780643100018160335021016&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1172711806124926227346822406879926575104066365513850591901167977031017773147553&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3494796072257580113875396010361380353105632085492892479603715336182682602428143&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5608690637230685977144014723666813959973503662453370415571851701179428151882882&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8889353256564968091064157105454996484998754991348566666564916601887263240881070&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4832198618558083182213501188928625277122728831796445123889707032846261305648630&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2527176048898518342591580941543224978208167594213111446673112848581061191825984&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1291021894031447958561527430552161385666081569185835507259834732917990092146589&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8117077934368522739843309368028814069423002395997449936891495583107309283509271&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1180077432800679370662483747523408021854844321836016009650358574989381886337852&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1722516883913145519094014205375128862340002341518180047810642843228568880540172&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3417922325879216322183112046755680152782225539937453280161300294135511699130848&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0976433759293246140554344092404212626999402181891603820290765820423321186458935&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1984485518225135337585187247603955326905920439923621172092130464391731498388744&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8750392578000721268878463072511675222925230106406594118598329633269324358794764&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4929066475821912729913815944439237132097525066761248367529760023296968812652711&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1354078624366444615698555226671150629567656072692570827367021777825853318746140&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2863318577339635525264674498700520998767957283494612638659115064541050609931927&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0626267703727694820552442716314957841578389580288169926927235290811137237887434&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4221841397313800123531757418475100660454200912589623058183943877051413097869194&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2339339754985429142461984170624136785051296102102697817632037910221364646864651&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9855796964298457614203439681372147302465919398126442059583983219983682993673878&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5195511144366725918343436684113783818943460018156359275075623210303933783990867&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1450770230403557029292899962005967013424432778295850913345133681904640414130225&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6074976712103846157531047532174675106877834562907257767751866399263004265826476&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2927779415738730155062074319337848630585696081256539500213340093725740025118088&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1549556332762444079547546812082703704589345493095057789148939194264110489919019&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4566170053142149254913384680974964028594308712215301647785051390937700375621904&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6850793920957951588471978130651986351908543266002688052663010508763853950782008&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2184664457189708083557342565742275344614046037371745586008320578024563750973078&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8918522749313602046891225282398255933496131418430638794803291508377033406843725&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5993318777198284973711860102116509775279126577240620025658230260626934855295524&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0163482197624118826096325983427230149324714688555788577159485966979794672252786&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2049579060682321390550407916111513505775215286804094663126348519235979240267931&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1393177415036576603095965158893137047832256486627193835346772464826381170364046&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9672727436992842647585191196834755720506018282532384722445185130057363544741494&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9620010167886013834746116804462363836560880757170533362435237472884909654085819&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2200315846789415790035979932125380804930427597237917426179754754825031469057587&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5408385218092192305802900158223031488228733997920493838052062060383233685427730&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2479303637471252558356068491271641497786414938837109276566129349124360527596986&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0939690673802611552820885948021359288569430897510414990828683956519429277901630&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3954037665434237643444138532861028612543250728043306643540240455527506302759025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2547253114427400839942700506775082503198395916277602696346477632254520324291510&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7176423995375530679412205690580599798550778233049642580773735945645101772412041&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9770061447364487938863821369661007066965634140967634082532169232884947757170676&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4001778436464233464495522570739848976059303542657842980445747616892332657374307&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3505719849994753220744681385854225182109628156151628193674787620122409837550175&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0873904989000402627417710830371222663052469412680310145900108150056384479011904&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2835209300157229749112634620468892621559922849964862659975166458450846483410310&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9108533277021935459848755879666329563851612903497154909548344186653653532596030&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1909102262515819267424216040525600483418895125777391628629285735284199384249913&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4569616259150374342828948745370477195614375418738814522169402762983961841736104&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6795438095408475881223956725863549758305981513146677968273034768754628733774741&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5601175386054118189600876918455578756071642172440419960753296039010117418642333&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0700157761536698272554982837358908293635750455157297675798024638098958969267103&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6863406950021125691193872800648046146136177370993251603456335654259717488367827&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4221891453042458615303763101765455461453483141839094655158338636716818847773378&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3089958604524376415306549473187862340575705348685942443697841897636463859949926&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4444464568286807145435412305718175821967958934523535510530750957533464207224580&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2279373368828019548205439249352189164575083536583721094688224573324098240189090&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5336968277502282844656778779596324101840145138970262636945152077842421376473220&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7492641493346476621126619083363859115527821109445021807274717048079752479814069&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8489075707866445180273917549185493159488867602009975459154326516617446093785735&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7657409659738148136025968774346968795138906298743560267773358615395905430092434&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4090587183336112957335092481531071573600577415752552329335484584825448451281828&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8397267947223750920443272557916925997060835636847307503958963847413230458654999&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1510218368567378788057116023931994479266585942028846093606765504042151064449401&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7535053560571943565326163798733090077562063019270432774405336624206120162684878&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2795961016400131165092351347259003395336488326011264715606875560607985355101479&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1760498444803027184543196012361666512501664115266209446783611568980849759393366&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9004607206787763941830633066297736259437811557856982004496007136271945140295164&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1021123058841472126203195417354602182201593697351601555663719500088120144234523&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6489841188841869277921900098197497636848312736842577887524394082685476810652434&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4368023998666968889307055236194661569426524463555778731728379410827687126847841&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9767542567328134223554830928399001003746312827667717886760656045983730239481725&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0247192299979431368314503262526820359421826762698555934534502139292008724527340&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8566373287784944330515935635629564982235980178134875308234950470548865802766425&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3860142806266365958072884321048903006167833769100547151312160642686817573070175&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8517347856656124090595544002510378196552188147101332012713619529417880258338847&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9548595874229820385574539354556804227765871124740709294288382971201998678678558&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1135393032892116765181068789505132747404363007086649489491404624220840121961493&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9770980821410301887703418151100099801563662384204228166203260763728750184267283&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0131194615371938999731752172864595591147593535783229858980094812827904216900881&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0264484164635513605434976822336090709152508883040986176420243997392303278619543&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7132483818824284005791373572104029624554831023783619373272102143855002602772145&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1625555397693952027234647740913597061447733291018249879406776786602117249183252&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3028866932885668665387107476073897428999191152484269358567755332923524842064600&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3794929412192609471679420879441380627388660584277219132508113058600032222404868&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2912812185436951502936757180777020507704813293182422695970566889605944405493165&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1013050164683342445192514465075993459075480256309099680013258781889270979210377&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2978191200620386753171174166739274414356307635252359045515977252139725132495302&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4643451106675617568043015073444443099894159838269138387489278049925887086707284&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7829572513234800005657626866917894409850513692287942317924246061209211855433159&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9474862901923613493886199119281189221558415812534549155894713481042125093206748&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5327877884372067603958264162802943954426330867112852706462838411380034486572690&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0832825677844671600199639823373591008100835318576086939856769129801540454104086&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1677822021197754242364262145059312498290181267047980332959890135114462272477083&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2267001649763807453258389353505463199327476285470780889266423077199955133598911&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4228000626496272875548822896127419699372645929502724379809375313984715132685176&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4622127184084472238931211915326009413737074357833496656532089093339434182463301&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4308133856938907909683630708624133178764345576977957526210285792755588339502313&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8908965753207073692034844982785108219589789141504389489294521808974273153775683&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4710352841094853913320997396720648350856909009547717827126308937619267105900330&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5101845147776164022119091114165228791856934734405699522377750777712347632477472&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1009173135645423776920173241282009759190193451325534130721465706915799208352319&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7599436014849832502702741642253476812447287458898351283245611697635355626967353&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1666248190388798775893317097285333032144668959144551590316718826094121548655064&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7327190413743862383571166391385591854324294967408637687666499017919659934556270&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6341760473807628223322195796330107447627192021125501916257505545056806593020009&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7877518699192190569125611877551646125360935329152981694983591991442830972118425&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6024578420108611596786779391910078283535602332400676206290364979979566874130677&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6262721807685562884678614519635750114010818380727834704599313495363241399979019&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0070441245844791323697888362361156445150402411489057842369956860981561106349532&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0427329254749281230185541338204013332686802017845355478766281601177626930879718&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3924781109376832016663185405467845874107109473909888472781931298639743129405819&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9018728534014004893438844921156199392052668509822766055873031732621412819415997&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5106658073874599600482906898626458321908644717727705714148184312035554569461172&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2571014234210898150511238337764888383510750920318252617219954833323650772315822&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8694765635893382122506622111504457282650772215884112102663088591828929423478423&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4630228876316754232955789012778765153858505693804419173581459528959967049577393&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3203503330240909044864203529502068033769777504652970513017398216284525619584395&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7399576075789549294657904493999442658423657409794863027890740986637503143358200&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1934990177507763078658788020042351989886877390781804018450451154174423611071016&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3402098758156739497049080279046203857466871438452835345118677125325469128068133&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1366454054797295342986762057003055457075865166635455089017691661317421628642115&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4993805637263456481774330967345531754745117304815930559577694749501153002539548&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5404256140871044730263074060283878378820730250169561914787775689729320033889071&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6450665587233640719268830704525315924153018596256798187945369509492198616718735&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1727110697661735449130358956047142033543848955222885833760237898733698724067547&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8419101187420106748225373809326555034920972273032855852671672606413074751824780&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5154501659974029329400410688611596507780739224024571262805816781734162995302986&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6056046847929263719956354500493986529434154889061593903845247605955487265601755&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6043989537334852057279780609368927725387526205357590787648273036069019155497325&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7284579301234574132272242978804776467287642325689728908190752748762036032550553&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0297580281513471442798728664035839834832168788094160691038978903832691745390723&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8280774908923640913005731937007494753031663001263187085109076785504199996190411&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2645973159719700472616661742318567810513248327998862965177705803004760763074321&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2313603449759152065701241959565937761991117902298693865777609004090724789824238&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3972666226870968534310397976577839690259724502877323852210276007099716458281622&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0266833622323608118226700555948541874878778700732590694206338358355846043998302&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2076998169472117379362890485627714537422759747305703434242979589456473320420530&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3798100254154945537756689378818628238489975669085399495869198707118002332356201&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2860990261282434269797439143900692337984204234325905652408969984088094424603914&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1324281031601472803905094128246361871536795078781179969095901324385165589352908&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5570928042409387112284705341815718794836739937616493333506970623215543845017075&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9783614942442566404035374016694617857746139989520230332862060498894309587704609&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2307147218032013573247425767983972450327115251550658313094143782360088885333289&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5608157274415946459185147621933085094399365522400749862053761657227728398780469&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7624550738125029927864820017089079162293784666905532642099274666498693255031122&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2889026525933407361948759134200215183348933115884125348251449445229741605009136&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5213445919902677380093249284489832185317941999559970629694476644944502557922299&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4045467263054565580347599600913022630568314834909143526070011238471771326443583&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5999517514967645625805546197521789593944893957635299668589873242979729214565080&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2261124045260532526154306748833731566597485067054072337617187788422439611692535&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6816154352988676611143089545607089006494597803681742408872009589972348314218354&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5885756829028538416517815718956811889863727858335798002033148984814372442071252&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2067544365025698588181983841271622441543580184070308095038169545529105805899001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5825565028451412722300055213104773432923209992505613530612435181227942384006400&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6523874291660768676182135558923684054785558197662748591717032047925055385422584&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8826587112169068650291428518318455696828296955217726852703371476729712500873714&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9472757285042561083989577043290348125840395005244750850424202067248954262318073&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3815815411200758900340511052777147951522351782525348580404031636340281256009099&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3622685663270098759448305092624146163465790024589793366278716865415624355235291&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3985878069536487297514629837101726802175517221106646456169044468305875210017956&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3762872046696988950422497705388225997904571624738961093738188347083184831994615&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5653340873908308859802165057177945265893576798033839250748977766722025452484918&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4969906442004769360577067228954632576483279588054785969942183381969384204862823&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5527295851917376805942967603231125591852023457112648669282453139677076502138626&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9831545895899997311194908866099892662200438185858903893802349550297108232343975&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7063807807&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Before you ask - yes, this is my PGP public key as a single decimal integer.&lt;&#x2F;p&gt;
&lt;p&gt;Next time you will see someone asking for &quot;shorter UUID&quot; you can point them
there and say - just pick shorter representation.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Stop Spreading Crap at My `$HOME`</title>
      <published>2020-04-15T00:00:00+00:00</published>
      <updated>2020-04-15T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/stop-spreading-crap-at-my-home/" type="text/html"/>
      <id>https://hauleth.dev/post/stop-spreading-crap-at-my-home/</id><content type="html">&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;&#x2F;strong&gt; Yes, this is a rant. Yes, I am displeased with state of
software. And yes, I can use some harsh words. You were warned.&lt;&#x2F;p&gt;
&lt;p&gt;For some time now we have &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Filesystem_Hierarchy_Standard&quot;&gt;Filesystem Hierarchy Standard&lt;&#x2F;a&gt; which describes
which data goes where in your *nix installation. In fact we have that for 28
years, which is almost as long as I live. This is quite some time. But for
whatever reason we apply that only for the system hierarchy and we cannot have
the same for something much closer to our heart - our dear &lt;code&gt;$HOME&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Common practice for storing all the stuff for different applications is to use
dot files stored in &lt;code&gt;$HOME&lt;&#x2F;code&gt;. These are files or directories starting with dot in
their name which makes such files &quot;hidden&quot; on Unix systems. There is problem
though. First let me show you all the files starting with dot in my &lt;code&gt;$HOME&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-r--------  1 hauleth staff     9 Mar 30  2019 .CFUserTextEncoding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 hauleth staff 16388 Apr  9 11:46 .DS_Store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------  2 hauleth staff    64 Apr 13 20:54 .Trash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-------  1 hauleth staff 17835 Apr 10 21:17 .bash_history&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------ 12 hauleth staff   384 Mar 30  2019 .bash_sessions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x 13 hauleth staff   416 Mar 26 14:02 .cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lrwxr-xr-x  1 hauleth staff    40 Aug 21  2019 .chunkwmrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x 20 hauleth staff   640 Apr 15 21:59 .config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------  3 hauleth staff    96 Apr 20  2019 .cups&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lrwxr-xr-x  1 hauleth staff    39 Aug 21  2019 .curlrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lrwxr-xr-x  1 hauleth staff    43 Aug 21  2019 .dir_colors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 hauleth staff  2587 Sep 10  2019 .direnvrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  6 hauleth staff   192 Apr 14 18:27 .docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------ 14 hauleth staff   448 Oct  1  2019 .dropbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-r--------  1 hauleth staff    20 Apr  1  2019 .erlang.cookie&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  3 hauleth staff    96 Jul  1  2019 .gem&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 hauleth staff   518 Mar 25 22:44 .gitconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------ 14 hauleth staff   448 Apr 15 22:03 .gnupg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  4 hauleth staff   128 Apr  2  2019 .hammerspoon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  5 hauleth staff   160 Apr 14 19:39 .hex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------  3 hauleth staff    96 Apr 26  2019 .httpie&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 hauleth staff   165 Feb 22 13:50 .jlassetregistry.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  3 hauleth staff    96 Nov 29 22:13 .jssc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  9 hauleth staff   288 Feb 21 17:46 .julia&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------ 14 hauleth staff   448 Oct  2  2019 .keychain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-x---  5 hauleth staff   160 Jan 24 12:20 .kube&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-------  1 hauleth staff   720 Apr 15 16:29 .lesshst&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-x---  3 root    staff    96 Apr  3  2019 .lldb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------  4 hauleth staff   128 Dec 18 14:16 .local&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  8 hauleth staff   256 Mar 20 12:29 .mitmproxy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x 18 hauleth staff   576 Apr 13 14:36 .mix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 hauleth staff   116 Apr 13 20:59 .nix-channels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  4 hauleth staff   128 Apr 14 13:47 .nix-defexpr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lrwxr-xr-x  1 hauleth staff    46 Feb  1 22:13 .nix-profile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  3 hauleth staff    96 Sep 27  2019 .npm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  3 hauleth staff    96 Dec 19 14:05 .pex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 hauleth staff   183 May  2  2019 .profile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  5 hauleth staff   160 Mar 20 16:27 .proxyman&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  2 hauleth staff    64 Feb 17 14:09 .proxyman-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-------  1 hauleth staff  1391 Jan 22 11:46 .psql_history&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-------  1 hauleth staff  1950 Feb 19 12:42 .python_history&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lrwxr-xr-x  1 hauleth staff    37 Aug 21  2019 .skhdrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------ 11 hauleth staff   352 Oct  2  2019 .ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  4 hauleth staff   128 May  8  2019 .terraform.d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  4 hauleth staff   128 Dec  1 21:52 .thumbnails&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  9 hauleth staff   288 Mar  9 17:14 .vagrant.d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-------  1 hauleth staff 11124 Apr 13 20:21 .viminfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lrwxr-xr-x  1 hauleth staff    37 Aug 21  2019 .vimrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwx------  4 hauleth staff   128 Nov  8 16:51 .w3m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x 37 hauleth staff  1184 Apr 13 21:21 .weechat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, there is bunch of them, some are linked to my dotfiles
repository, but most are not. What is the problem there?&lt;&#x2F;p&gt;
&lt;p&gt;The spread.&lt;&#x2F;p&gt;
&lt;p&gt;All the data is smeared between gazillion of different filed with different
types of data. This causes headaches because:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I cannot easily backup all the configuration as I need to check each file
independently to check if this is configuration file or it is data&lt;&#x2F;li&gt;
&lt;li&gt;I cannot exclude data from my backups in a uniform way. I need to check each
file independently and exclude it, remembering to do that for each new tool
that I add. Alternatively, I can use whitelist instead of blacklist of paths
that I want backup, but that pretty much defies the idea of having
automatic backup.&lt;&#x2F;li&gt;
&lt;li&gt;Cleaning up the old caches and data is troublesome as user need to review all
the folders and know what data they see mean.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But what We can do? Well, the macOS, and Windows got it somewhat right, these
OSes provide special paths for storing all configuration, caches, user-data,
etc. in special, dedicated, and well known locations within user directories. It
is like mentioned earlier FHS but for &lt;code&gt;$HOME&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately no other OS out there had:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Power to force developers to behave reasonably&lt;&#x2F;li&gt;
&lt;li&gt;Standard to which developers should adhere to&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Unfortunately the 1st point is still true, but the 2nd one is somewhat resolved
in form of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;specifications.freedesktop.org&#x2F;basedir-spec&#x2F;latest&#x2F;index.html&quot;&gt;XDG Base Directory Specification&lt;&#x2F;a&gt;. This is pretty short,
simple, and straightforward spec where which data should go.&lt;&#x2F;p&gt;
&lt;p&gt;This makes life so much easier:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Want to have backup your configuration? Just copy &lt;code&gt;$HOME&#x2F;.config&lt;&#x2F;code&gt; where you
want.&lt;&#x2F;li&gt;
&lt;li&gt;Want to reset your configuration to base one? Just delete &lt;code&gt;$HOME&#x2F;.config&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Want to clean up caches? Remove &lt;code&gt;$HOME&#x2F;.cache&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It makes your &lt;code&gt;$HOME&lt;&#x2F;code&gt; much cleaner, much more manageable, much more like your
place, where you are the ruler, not as a manager of the bulletin board or the
storage house.&lt;&#x2F;p&gt;
&lt;p&gt;At one point I was even considering to have approach similar to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;erase-your-darlings&quot;&gt;one taken by
Graham Christensen&lt;&#x2F;a&gt;, but that would make my life even more
miserable instead of forcing developers to fix their software.&lt;&#x2F;p&gt;
&lt;p&gt;Just in case, this is not only mine view on the state of configuration files,
just see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20180827160401&#x2F;plus.google.com&#x2F;+RobPikeTheHuman&#x2F;posts&#x2F;R58WgWwN9jp&quot;&gt;old Google+ post by Rob Pike&lt;&#x2F;a&gt; where he states exactly the same
thing that FreeDesktop team try to address. I may not agree on all the concepts
with Commander, but this one I vote all-fours.&lt;&#x2F;p&gt;
&lt;p&gt;For these who want to stop that madness and fix at least some software out there
that is broken, you can check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hauleth&#x2F;xdg-rlz&quot;&gt;my script&lt;&#x2F;a&gt; that tries to fix
(at least partially) nonconforming software.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Please, stop leaving your c**p in my &lt;code&gt;$HOME&lt;&#x2F;code&gt; and call it &quot;installation&quot;. If
you want that, then I think you should find nearest Modern Art Gallery.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;You can comment it on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;va7gic&#x2F;stop_spreading_c_p_at_my_home&quot;&gt;Lobste.rs&lt;&#x2F;a&gt;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;g2210g&#x2F;stop_spreading_cp_at_my_home&#x2F;&quot;&gt;Reddit&lt;&#x2F;a&gt;
or @ me on Twitter.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Writing Vim Plugin</title>
      <published>2019-11-04T00:00:00+00:00</published>
      <updated>2019-11-04T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/writing-vim-plugin/" type="text/html"/>
      <id>https://hauleth.dev/post/writing-vim-plugin/</id><summary>Article about writing Vim plugins, but not about writing Vim plugins. It is
how to conceive plugin, how to go from an idea to the full fledged plugin.</summary><content type="html">&lt;p&gt;While there are many &quot;tutorials&quot; for writing plugins in Vim, I hope this one
will be a little bit different from what is out there, because it won&#x27;t be
about writing plugin &lt;em&gt;per se&lt;&#x2F;em&gt;. If you want to find information about that then
you should check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;usr_41.txt.html#write-plugin&quot;&gt;&lt;code&gt;:h write-plugin&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. I want this article to be about how
plugins come to life, using my own experience on writing
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hauleth&#x2F;vim-backscratch&quot;&gt;&lt;code&gt;vim-backscratch&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; as an example.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;a class=&quot;zola-anchor&quot; href=&quot;#problem&quot; aria-label=&quot;Anchor link for: problem&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;All plugins should start with a problem. If there is no problem, then there
should be no code, as there is no better code than &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kelseyhightower&#x2F;nocode&quot;&gt;no code&lt;&#x2F;a&gt;. In this
case, my problem was pretty trivial: I wanted a temporary buffer that would let
me perform quick edits and view SQL queries while optimising them (and run them
from there with Tim Pope&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-dadbod&quot;&gt;dadbod&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;simple-obvious-solution&quot;&gt;&quot;Simple obvious solution&quot;&lt;a class=&quot;zola-anchor&quot; href=&quot;#simple-obvious-solution&quot; aria-label=&quot;Anchor link for: simple-obvious-solution&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we have defined the problem, we need to try the first possible solution.
In our case, it is opening a new buffer in a new window, edit it, and then close it
when no longer needed. It is simple in Vim:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&amp;quot; Edits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:bd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately this has bunch of problems:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If we forgot to close that buffer, then it will hang there indefinitely,&lt;&#x2F;li&gt;
&lt;li&gt;running &lt;code&gt;:bd!&lt;&#x2F;code&gt; in the wrong buffer, can have unpleasant consequences,&lt;&#x2F;li&gt;
&lt;li&gt;This buffer is still listed in &lt;code&gt;:ls&lt;&#x2F;code&gt;, which is unneeded (as it is only
temporary).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;systematic-solution-in-vim&quot;&gt;Systematic solution in Vim&lt;a class=&quot;zola-anchor&quot; href=&quot;#systematic-solution-in-vim&quot; aria-label=&quot;Anchor link for: systematic-solution-in-vim&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Fortunately Vim has solutions for all of our problems:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &quot;scratch&quot; section in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;windows.txt.html#special-buffers&quot;&gt;&lt;code&gt;:h special-buffers&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which
solves the first two problems,&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;windows.txt.html#unlisted-buffer&quot;&gt;&lt;code&gt;:h unlisted-buffer&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which solves the third problem.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So now our solution looks like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;setlocal&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; nobuflisted buftype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;nofile &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;bufhidden&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;delete &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;noswapfile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&amp;quot; Edits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:bd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, that is a long chain of commands to write. Of course we could condense
the first two into a single one:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:new &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;nobuflisted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;buftype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;nofile &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;bufhidden&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;delete &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;noswapfile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But in reality this does not shorten anything.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;create-a-command&quot;&gt;Create a command&lt;a class=&quot;zola-anchor&quot; href=&quot;#create-a-command&quot; aria-label=&quot;Anchor link for: create-a-command&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Fortunately we can create our own commands in Vim, so we can shorten that to a
single, easy to remember command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; Scratch new &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;nobuflisted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;buftype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;nofile &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;bufhidden&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;delete &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span&gt;noswap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For better flexibility, I prefer it to be:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; Scratchify &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;setlocal&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; nobuflisted buftype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;nofile &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;bufhidden&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;delete noswap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; Scratch new &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can also add a bunch of new commands to give us better control over our new
window&#x27;s location:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; VScratch vnew &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; TScratch tabnew &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Those commands will open a new scratch buffer in a new vertical window, and
a new scratch buffer in a new tab page, respectively.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;make-it-a-more-vimmy-citizen&quot;&gt;Make it a more &quot;vimmy&quot; citizen&lt;a class=&quot;zola-anchor&quot; href=&quot;#make-it-a-more-vimmy-citizen&quot; aria-label=&quot;Anchor link for: make-it-a-more-vimmy-citizen&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;While our commands &lt;code&gt;:Scratch&lt;&#x2F;code&gt;, &lt;code&gt;:VScratch&lt;&#x2F;code&gt;, and &lt;code&gt;:TScratch&lt;&#x2F;code&gt; are nice, they are
still not flexible enough. In Vim we can use modifiers like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;windows.txt.html#%3Aaboveleft&quot;&gt;&lt;code&gt;:h :aboveleft&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to define exactly where we want new windows to appear
and our current commands do not respect that. To fix this problem, we can
simply squash all the commands into one:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; Scratch &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;new &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we can remove &lt;code&gt;:VScratch&lt;&#x2F;code&gt; and &lt;code&gt;:TScratch&lt;&#x2F;code&gt; as these can be now done via
&lt;code&gt;:vert Scratch&lt;&#x2F;code&gt; and &lt;code&gt;:tab Scratch&lt;&#x2F;code&gt; (of course you can keep them if you like, I
just wanted the UX to be minimal).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;make-it-powerful&quot;&gt;Make it powerful&lt;a class=&quot;zola-anchor&quot; href=&quot;#make-it-powerful&quot; aria-label=&quot;Anchor link for: make-it-powerful&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This has been in my &lt;code&gt;$MYVIMRC&lt;&#x2F;code&gt; for some time in the form described above until
I found out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;romainl&#x2F;eae0a260ab9c135390c30cd370c20cd7&quot;&gt;Romain Lafourcade&#x27;s snippet&lt;&#x2F;a&gt; that provided one additional
feature: it allowed to open a scratch buffer with the output of a Vim or shell
command. My first thought was - hey, I know that, but I know I can make it
better! So we can write a simple VimL function (which is mostly copied from
romainl&#x27;s snippet, with a few improvements):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;function!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; s:scratch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; abort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    elseif&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;!&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =~&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39; %&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; substitute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39; %&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; . &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;expand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;%:p&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; systemlist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;matchstr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;^!\zs.*&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; split&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;\n&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;    execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; . &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39; new&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; setline&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;endfunction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; Scratchify &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;setlocal&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; nobuflisted noswapfile buftype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;nofile &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;bufhidden&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;delete&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command! -nargs=1 -complete=command&lt;&#x2F;span&gt;&lt;span&gt; Scratch &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;SID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;scratch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&amp;lt;mods&amp;gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;q-args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The main differences are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Special case for empty command, it will just open an empty buffer,&lt;&#x2F;li&gt;
&lt;li&gt;Use of &lt;code&gt;is#&lt;&#x2F;code&gt; instead of &lt;code&gt;==&lt;&#x2F;code&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;Use of &lt;code&gt;:h execute()&lt;&#x2F;code&gt; instead of &lt;code&gt;:redir&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As it is quite self-contained and (let&#x27;s be honest) too specific for &lt;code&gt;$MYVIMRC&lt;&#x2F;code&gt;
we can extract it to its own location in &lt;code&gt;plugin&#x2F;scratch.vim&lt;&#x2F;code&gt;. To do so properly
we need one additional thing, a command to prevent the script from being loaded
twice:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; exists&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;g:loaded_scratch&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    finish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; g:loaded_scratch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;function!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; s:scratch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; abort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    elseif&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;!&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =~&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39; %&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; substitute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39; %&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; . &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;expand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;%:p&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; systemlist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;matchstr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;^!\zs.*&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; split&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;\n&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;    execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; . &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39; new&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; setline&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;endfunction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command!&lt;&#x2F;span&gt;&lt;span&gt; Scratchify &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;setlocal&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; nobuflisted noswapfile buftype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;nofile &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;bufhidden&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;delete&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;command! -nargs=1 -complete=command&lt;&#x2F;span&gt;&lt;span&gt; Scratch &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;SID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;scratch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;q-mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;, &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;q-args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;to-boldly-go&quot;&gt;To boldly go…&lt;a class=&quot;zola-anchor&quot; href=&quot;#to-boldly-go&quot; aria-label=&quot;Anchor link for: to-boldly-go&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now my idea was, hey, I use Vim macros from time to time, and these are just
simple lists of keystrokes stored in Vim registers. Maybe it would be nice to have
access to that as well in our command. So we will just add a new condition that
checks if &lt;code&gt;a:cmd&lt;&#x2F;code&gt; begins with the &lt;code&gt;@&lt;&#x2F;code&gt; sign and has a length of two. If so, then
set &lt;code&gt;l:output&lt;&#x2F;code&gt; to the spliced content of the register:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;function!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; s:scratch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; abort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    elseif&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;@&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; strlen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getreg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; v:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            throw&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;Invalid register&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    elseif&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;is&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;!&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =~&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39; %&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; substitute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39; %&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; . &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;expand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;%:p&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; systemlist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;matchstr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;^!\zs.*&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; split&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;a:cmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;\n&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;    execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; a:mods&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; . &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39; new&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Scratchify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; setline&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;endfunction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gives us a pretty powerful solution where we can use &lt;code&gt;:Scratch @a&lt;&#x2F;code&gt; to open
a new scratch buffer with the content of register &lt;code&gt;A&lt;&#x2F;code&gt;, edit it, and yank it
back via &lt;code&gt;&quot;ayy&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pluginize&quot;&gt;Pluginize&lt;a class=&quot;zola-anchor&quot; href=&quot;#pluginize&quot; aria-label=&quot;Anchor link for: pluginize&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now, it would be a shame to keep such a useful tool for ourselves so
let&#x27;s share it with the big world. In this case we need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a proper project structure,&lt;&#x2F;li&gt;
&lt;li&gt;documentation,&lt;&#x2F;li&gt;
&lt;li&gt;a good catchy name.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can find help on the two first topics in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;usr_41.txt.html#write-plugin&quot;&gt;&lt;code&gt;:h write-plugin&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;usr_41.txt.html#write-local-help&quot;&gt;&lt;code&gt;:h write-local-help&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
or in any of the bazillion tutorials on the internet.&lt;&#x2F;p&gt;
&lt;p&gt;Finding a good name is something I can&#x27;t help you with. I have picked
&lt;code&gt;vim-backscratch&lt;&#x2F;code&gt;, because I like back scratches (everyone likes them) and, as
a nice coincidence, because it contains the word &quot;scratch&quot;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Creating plugins for Vim is easy, but not every functionality needs to be
a plugin from day one. Start easy and small. If something can be done with
a simple command&#x2F;mapping, then it should be done with a simple command&#x2F;mapping
at first. If you find your solution really useful, then, and only then, you
should think about turning it into a plugin. The whole process described in this
article didn&#x27;t happen in a week or two. It took me about a year to reach the step
&lt;em&gt;Make it a more &quot;vimmy&quot; citizen&lt;&#x2F;em&gt;, when I heard about romainl&#x27;s script on IRC.
I didn&#x27;t need anything more, so take your time.&lt;&#x2F;p&gt;
&lt;p&gt;Additional pro-tips:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Make it small, big plugins will require a lot of maintenance, small plugins
are much simpler to maintain,&lt;&#x2F;li&gt;
&lt;li&gt;If something can be done via a command then it should be made as a command,
do not force your mappings on users.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Let&#x27;s talk about `application&#x2F;0`</title>
      <published>2019-07-26T00:00:00+00:00</published>
      <updated>2019-07-26T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/elixir-application/" type="text/html"/>
      <id>https://hauleth.dev/post/elixir-application/</id><summary>Have you ever thought about that one simple function in your `mix.exs`? It
comes out as quite powerful and useful place for storing configuration and
post-launch scripts.</summary><content type="html">&lt;p&gt;When you start your new Elixir project via &lt;code&gt;mix new my_awesome_project&lt;&#x2F;code&gt; you will
end with something like this in &lt;code&gt;mix.exs&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; MyAwesomeProject&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Mixfile&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Mix&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Project&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;my_awesome_project&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # …&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      deps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; deps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; application&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      extra_applications&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  defp&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; deps&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # …&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And in most cases you will focus on &lt;code&gt;deps&#x2F;0&lt;&#x2F;code&gt;, sometimes on &lt;code&gt;config&#x2F;0&lt;&#x2F;code&gt;, but the
&lt;code&gt;application&#x2F;0&lt;&#x2F;code&gt; you will almost never touch, and if you do, you probably will only
need it to add new entry in &lt;code&gt;:extra_applications&lt;&#x2F;code&gt; or sometimes
&lt;code&gt;:included_applications&lt;&#x2F;code&gt;. Except for, that this function interns are terra
incognita, a place where you never look unless you are forced to, like &quot;Read
it later&quot; list in Safari. This is sad, as it is quite powerful and useful
piece of code.&lt;&#x2F;p&gt;
&lt;p&gt;However first things first.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-application-0-is-for&quot;&gt;What &lt;code&gt;application&#x2F;0&lt;&#x2F;code&gt; is for?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-application-0-is-for&quot; aria-label=&quot;Anchor link for: what-application-0-is-for&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In Erlang the running system is built from applications. Those applications are
like processes in your system managed by your system supervisor (SysV, systemd,
OpenRC, launchd, etc.). They are launched either during VM startup or on
direct user request via &lt;code&gt;Application.start&#x2F;1-2&lt;&#x2F;code&gt; and its family. Starting
this application is described in &lt;code&gt;my_awesome_app.app&lt;&#x2F;code&gt; file which is commonly
generated by the build system from the template. In Rebar3 projects this
template is &lt;code&gt;src&#x2F;appname.app.src&lt;&#x2F;code&gt; and in Elixir it&#x27;s the return value of the
named &lt;code&gt;application&#x2F;0&lt;&#x2F;code&gt; function. This generated file is known as &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.erlang.org&#x2F;doc&#x2F;design_principles&#x2F;applications.html#application-resource-file&quot;&gt;Application
Resource File&lt;&#x2F;a&gt;. It is just tuple in form of &lt;code&gt;{:application, :my_awesome_app, opts}&lt;&#x2F;code&gt; where &lt;code&gt;opts&lt;&#x2F;code&gt; is a keyword list of additional properties
(to be exact it&#x27;s output of the &lt;code&gt;application&#x2F;0&lt;&#x2F;code&gt; function).&lt;&#x2F;p&gt;
&lt;p&gt;Two of those optional fields are quite known in the Elixir community:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:mod&lt;&#x2F;code&gt; which is a tuple &lt;code&gt;{module(), term()}&lt;&#x2F;code&gt; containing the starting point
of our application; in most cases this is the module that will return main
supervisor of the application.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:applications&lt;&#x2F;code&gt; contains all applications required by our application; younger
Elixir developers possibly never seen that as since version 1.5 this field
is automatically filled by parsing &lt;code&gt;:deps&lt;&#x2F;code&gt;, though we still can add entries
there via &lt;code&gt;:extra_applications&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are also few Elixir specific fields, sometimes used in larger projects:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:extra_applications&lt;&#x2F;code&gt; - those should be included in the release
and automatically started before running current application; but aren&#x27;t in the
dependencies list because, for example, are in default distribution, for
example &lt;code&gt;logger&lt;&#x2F;code&gt; or &lt;code&gt;inets&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;:included_applications&lt;&#x2F;code&gt; - applications which should be included in the
release, but not automatically started on boot.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Wait, there is more!&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately not all of the highly useful keys are used&#x2F;known in the community.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;application-environment&quot;&gt;Application environment&lt;a class=&quot;zola-anchor&quot; href=&quot;#application-environment&quot; aria-label=&quot;Anchor link for: application-environment&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;For some reason everyone calls it configuration. If you are familiar with
&lt;code&gt;config&#x2F;config.exs&lt;&#x2F;code&gt; and for some reason you decided to go &lt;a href=&quot;https:&#x2F;&#x2F;hauleth.dev&#x2F;post&#x2F;elixir-application&#x2F;guidelines&quot;&gt;against the &lt;em&gt;Library
Guidelines&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; and you have decided to use application environment for
configuring your code (there are reason to do so, even when you publish your
code as a &quot;library&quot;, see &lt;code&gt;lager&lt;&#x2F;code&gt; or &lt;code&gt;opencensus&lt;&#x2F;code&gt;) then you will soon find that
putting configuration in your&#x27;s library &lt;code&gt;config&#x2F;config.exs&lt;&#x2F;code&gt; do not matter much
in it&#x27;s dependants. You have 2 possibilities how to solve that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Application.get_env&#x2F;3&lt;&#x2F;code&gt; and define your &quot;default&quot; as a 3rd argument.&lt;&#x2F;li&gt;
&lt;li&gt;Use &lt;code&gt;:env&lt;&#x2F;code&gt; to set data that should be loaded to application environment by
default.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Be wary that the second option works only for current application, so you
cannot configure other applications (for example &lt;code&gt;logger&lt;&#x2F;code&gt;) there. &lt;em&gt;But what is
the point?&lt;&#x2F;em&gt; You may ask, and I found one. If you want to use default
&lt;code&gt;sys.config&lt;&#x2F;code&gt; file for configuring your application then sometimes few pointless
configuration option can land there, like &lt;code&gt;:ecto_repos&lt;&#x2F;code&gt; variable which truly
doesn&#x27;t matter much in production as it&#x27;s only used by Ecto&#x27;s Mix tasks. What
I do is to add new entry in &lt;code&gt;application&#x2F;0&lt;&#x2F;code&gt; with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ecto_repos&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;MyAwesomeApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And call it a day. Now I can focus on keeping &lt;strong&gt;real&lt;&#x2F;strong&gt; configuration options in
&lt;code&gt;config&#x2F;config.exs&lt;&#x2F;code&gt; and remove unneeded fields from there. But remember that you
still can override these values by setting them in &lt;code&gt;sys.config&lt;&#x2F;code&gt; if needed, so
this is pure win for me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;start-phases&quot;&gt;Start phases&lt;a class=&quot;zola-anchor&quot; href=&quot;#start-phases&quot; aria-label=&quot;Anchor link for: start-phases&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Application configuration also allows you to define additional pieces of code to
be run after your application started. For example, imagine situation when you
want to send Slack notification that given node started and is ready to work.
You can do it via temporary task in &lt;code&gt;Supervisor.init&#x2F;2&lt;&#x2F;code&gt; by defining child list
like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;  MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;  MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;  {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Task&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; &amp;amp;send_slack_notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Alternatively, you can use &lt;code&gt;:start_phases&lt;&#x2F;code&gt; in &lt;code&gt;application&#x2F;0&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;start_phases&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  notify&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then define in your &lt;code&gt;Application&lt;&#x2F;code&gt; module function &lt;code&gt;start_phase&#x2F;3&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; start_phase&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;notify&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;normal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; send_slack_notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Where 1st argument will be the name of the phase, 2nd will be start type the
same as in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;Application.html#c:start&#x2F;2&quot;&gt;&lt;code&gt;Application.start&#x2F;2&lt;&#x2F;code&gt; callback&lt;&#x2F;a&gt;,
and 3rd is the value passed in &lt;code&gt;:start_phases&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The awesome part there is that &lt;code&gt;start_phase&#x2F;3&lt;&#x2F;code&gt; is called not only for current
application, but all of its dependencies as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;registered-names&quot;&gt;Registered names&lt;a class=&quot;zola-anchor&quot; href=&quot;#registered-names&quot; aria-label=&quot;Anchor link for: registered-names&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This is one of the things that had more sense in Erlang world than in Elixir,
but by being good citizen we should use it as well. This is a nice solution for
lack of namespacing in Erlang - it allowed release tools to detect collisions in
named processes. This is simple list of atoms that contain all names that are
globally registered by this application. Example form &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elixir-lang&#x2F;elixir&#x2F;blob&#x2F;ee9f38635e9a6c816adb575fc9431ded49be8032&#x2F;lib&#x2F;logger&#x2F;mix.exs#L14&quot;&gt;Elixir&#x27;s
Logger&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;registered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;BackendSupervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Supervisor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; Logger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Watcher&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately Phoenix do not use this field itself and do not suggest using one
in its default project generator. But in general it&#x27;s good practise.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;There is much more in application configuration to what most Elixir code is
using, it is worth sometimes to read how your application is defined and ran.
For more information about generating application description file you can check
out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;mix&#x2F;Mix.Tasks.Compile.App.html&quot;&gt;&lt;code&gt;mix help compile.app&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Common Test for Elixir developers</title>
      <published>2019-07-15T00:00:00+00:00</published>
      <updated>2019-07-15T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/common-test-for-elixir/" type="text/html"/>
      <id>https://hauleth.dev/post/common-test-for-elixir/</id><content type="html">&lt;p&gt;In my new job I have opportunity to work a little bit more with Erlang code and
Erlang related tools than earlier.  That forced me a little to learn and use
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;apps&#x2F;common_test&#x2F;basics_chapter.html&quot;&gt;Common Test&lt;&#x2F;a&gt; library which is &lt;strong&gt;the&lt;&#x2F;strong&gt; testing library in Erlang world.
When after that I needed to work back it hit me hard how much stuff I am
missing in Elixir.  In this article I will try to present Common Test library
from the viewpoint of long standing Elixir guy and present how it compares to
the ExUnit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unit-testing-vs-integration-testing&quot;&gt;Unit testing vs integration testing&lt;a class=&quot;zola-anchor&quot; href=&quot;#unit-testing-vs-integration-testing&quot; aria-label=&quot;Anchor link for: unit-testing-vs-integration-testing&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The main difference between these two is their intended usage.  In its core,
ExUnit is intended as a library for unit testing (no surprise there, as it is
literally in it&#x27;s name). On the other hand, Common Test is more about integration
testing and looking on the system as a whole. So the discussion there would not
be fair, as it isn&#x27;t apples to apples, but for second let&#x27;s check what makes
each of them great for their intended uses:&lt;&#x2F;p&gt;
&lt;p&gt;ExUnit for unit testing:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Simple way to setup and teardown tests via &lt;code&gt;setup&lt;&#x2F;code&gt; and &lt;code&gt;setup_all&lt;&#x2F;code&gt; macros&lt;&#x2F;li&gt;
&lt;li&gt;Built-in testing of documentation examples via &lt;code&gt;doctest&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Immutability of test environment (at least that is what you should try to
achieve)&lt;&#x2F;li&gt;
&lt;li&gt;Very simple way of running different test modules in parallel (tests within
single module are always sync)&lt;&#x2F;li&gt;
&lt;li&gt;Each test run in separate process, which prevents sharing data between
processes via process dictionary&lt;&#x2F;li&gt;
&lt;li&gt;Grouping tests into &lt;code&gt;describe&lt;&#x2F;code&gt; blocks&lt;&#x2F;li&gt;
&lt;li&gt;In overall simplicity of the library as a whole&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Common Test for integration testing:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Persistent test results - logs, results, &quot;generated garbage&quot; is stored between
runs in the Common Test, which allows tracking what and when happened, and if
needed trace the bug in the logs&#x2F;leftovers&lt;&#x2F;li&gt;
&lt;li&gt;Generating &quot;private directory&quot; per suite&lt;&#x2F;li&gt;
&lt;li&gt;Grouping tests while allowing single test to be reused in different groups&lt;&#x2F;li&gt;
&lt;li&gt;Extensive control about order and parallelization of tests within groups&lt;&#x2F;li&gt;
&lt;li&gt;Built-in very extensive and detailed reports (HTML and JUnit)&lt;&#x2F;li&gt;
&lt;li&gt;Distributed testing&lt;&#x2F;li&gt;
&lt;li&gt;Define dependencies between tests&lt;&#x2F;li&gt;
&lt;li&gt;Set of helpers for working with different network protocols (SSH, Telnet,
SNMP, FTP, Erlang RPC, netconf)&lt;&#x2F;li&gt;
&lt;li&gt;Built-in support for data fixtures&lt;&#x2F;li&gt;
&lt;li&gt;Built-in support for complex configuration of test runs via &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;apps&#x2F;common_test&#x2F;run_test_chapter.html#test-specifications&quot;&gt;test
specifications&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Built-in logging (we will cover that later)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So as you can see, the Common Test is much broader and complex, but at the same
time it provides a lot of utilities that are really helpful while writing
integration tests, that can span multiple applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;writing-common-test-suite&quot;&gt;Writing Common Test suite&lt;a class=&quot;zola-anchor&quot; href=&quot;#writing-common-test-suite&quot; aria-label=&quot;Anchor link for: writing-common-test-suite&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;While CT provides enormous power in hand of the experienced tester&#x2F;developer
it&#x27;s API isn&#x27;t the top of the class. It happens a lot in Erlang tools, whoever
wanted to integrate them with anything then they will know what I mean). But in
fact writing simple test suite in CT is fairly easy:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;module&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;example_SUITE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-punctuation z-section&quot;&gt;).&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; % The naming convention (with uppercase _SUITE) Erlang&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                        % convention which allow ct to find test suites.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                        % Something like ExUnit _test.exs naming convention&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;export&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-definition z-parameters z-punctuation z-section&quot;&gt;]).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;export&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;test_function_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-definition z-parameters z-punctuation z-section&quot;&gt;]).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    [&lt;&#x2F;span&gt;&lt;span&gt;test_function_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;test_function_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;_Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;    2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is pretty easy and understandable format, but with due CT power it &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlang&#x2F;otp&#x2F;blob&#x2F;81d332cc693d2be8a5af16bfbcae0bfde6702479&#x2F;lib&#x2F;ssh&#x2F;test&#x2F;ssh_algorithms_SUITE.erl#L36&quot;&gt;quickly
can grow to be &quot;less&quot; readable&lt;&#x2F;a&gt;.
Taming that power can be problematic and can cause few headaches for newcomers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reporting&quot;&gt;Reporting&lt;a class=&quot;zola-anchor&quot; href=&quot;#reporting&quot; aria-label=&quot;Anchor link for: reporting&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Another part, and the one that I miss in ExUnit, is reporting in Common Test.
This alone is in my humble opinion &lt;strong&gt;THE&lt;&#x2F;strong&gt; best part of the library. To present
you how this work assume that we have above test suite which we will run with
&lt;code&gt;ct_run -dir .&lt;&#x2F;code&gt;. This will compile and run our tests (obviously), but in
addition to that it will generate hell lot of cruft files, some JQuery (yes,
this is still used in 2019), some CSS files, some HTML and other.&lt;&#x2F;p&gt;
&lt;p&gt;Just check &lt;a href=&quot;&#x2F;common-test-example&#x2F;simple&#x2F;index.html&quot;&gt;this out&lt;&#x2F;a&gt;. This is example
report generated by the Common Test. As you can see it contains a lot of
information in readable format. Not only it contains information about current
run, but all previous runs as well, which is really handy when tracking
regressions.&lt;&#x2F;p&gt;
&lt;p&gt;But can we store even more information there? Yes, as CT includes simple
logging facility it is completely possible to log your own information during
tests, for example, let&#x27;s modify our test to log some information:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;test_function_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;_Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    ct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Example message&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-definition z-parameters&quot;&gt;&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;    2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now when we run tests again, then we will see more information (even coloured)
in &lt;a href=&quot;&#x2F;common-test-example&#x2F;log&#x2F;ct_run.ct@NiunioBook.2019-07-16_11.03.21&#x2F;common-test-example.log.logs&#x2F;run.2019-07-16_11.03.22&#x2F;example_suite.test_function_name.html&quot;&gt;our test log&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;common-test&#x2F;log.png&quot; alt=&quot;Common Test log &amp;quot;Example message&amp;quot; on green background&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, there is support Surefire XML output (commonly known as JUnit XML)
via &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;apps&#x2F;common_test&#x2F;ct_hooks_chapter.html#built-in-cths&quot;&gt;hook that is distributed with Common Test&lt;&#x2F;a&gt;.
This is very useful, as many CI services (for sure Jenkins, Circle CI, and
GitLab CI) support such files to provide better CI results than raw stdout.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;comparison-to-exunit&quot;&gt;Comparison to ExUnit&lt;a class=&quot;zola-anchor&quot; href=&quot;#comparison-to-exunit&quot; aria-label=&quot;Anchor link for: comparison-to-exunit&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ExUnit is great tool, which is very flexible while being relatively simple.
Unfortunately that simplicity makes it very lacking when comparing with &quot;more
established&quot; solutions like Common Test which shines when we &quot;grow out&quot; of the
ExUnit tests. It provides a lot great tools that really help with finding bugs.
For example when I was joining the project and I was trying to run tests
locally I have some issues due to misconfiguration. It was much easier to send
tarball of the test results instead of sending wall of text captured from
stdout.&lt;&#x2F;p&gt;
&lt;p&gt;Don&#x27;t get me wrong, ExUnit is great and powerful, and for sure you should use
it. It is great evolution over EUnit, but again, it would be worth of having
built-in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.erlang.org&#x2F;doc&#x2F;man&#x2F;eunit_surefire.html&quot;&gt;Surefire XML output&lt;&#x2F;a&gt;
due to its popularity and support in many CI services.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;future&quot;&gt;Future&lt;a class=&quot;zola-anchor&quot; href=&quot;#future&quot; aria-label=&quot;Anchor link for: future&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;But is everything lost and we need to fall back to the Erlang code (which can be
problematic for many people) to use Common Test? Not exactly, Comcast (yes, that
Comcast) &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Comcast&#x2F;ctex&quot;&gt;created simple wrapper&lt;&#x2F;a&gt; for Elixir (unfortunately seems pretty
dead to me) and I have started &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hauleth&#x2F;commoner&quot;&gt;Commoner&lt;&#x2F;a&gt; library that is meant to
provide API more familiar and easier to use:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;defmodule&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Commoner&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;ExampleSuite&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  use&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt; CommonTest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;Suite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    assert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  test &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;bar baz&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-class&quot;&gt;    CommonTest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I am very interested in your feelings about Common Test usage in Elixir and
about proposed API for Commoner. You can ping me:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;On &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;elixirforum.com&#x2F;t&#x2F;commoner-elixir-wrapper-for-common-test-library&#x2F;23966?u=hauleth&quot;&gt;Elixir forum thread about Commoner&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;On Twitter via &lt;code&gt;@hauleth&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Here be (owned) books</title>
      <published>2019-07-14T00:00:00+00:00</published>
      <updated>2019-07-14T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/eli5-ownership/" type="text/html"/>
      <id>https://hauleth.dev/post/eli5-ownership/</id><summary>Simple introduction to Rust&#x27;s ownership system</summary><content type="html">&lt;p&gt;One of Rust&#x27;s biggest pros is its unique ownership system. Unfortunately, it is
also one of the hardest things to learn. In this article I will try to explain
it the same way I had learned it and how I introduce it to people.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;&#x2F;strong&gt;: If you do not find this article helpful try to search for another.
People are different and different things &lt;em&gt;zing&lt;&#x2F;em&gt; them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;let-s-have-a-book&quot;&gt;Let&#x27;s have a book&lt;a class=&quot;zola-anchor&quot; href=&quot;#let-s-have-a-book&quot; aria-label=&quot;Anchor link for: let-s-have-a-book&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Ownership becomes simple and natural if you just acknowledge it as an
application of real world relationships. For example, imagine types in Rust as
a kind of written note. We have different types of notes and based on that, each
of them will be handled differently.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Short ones, like phone no. of the hot waiter&#x2F;waitress&lt;&#x2F;li&gt;
&lt;li&gt;Longer ones, like this article&lt;&#x2F;li&gt;
&lt;li&gt;Longest ones, like a &lt;em&gt;Lord of the Rings&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Using this analogy let me try to introduce you, dear reader, to the amazing
world of Rust&#x27;s ownership.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-can-own-the-book&quot;&gt;One can own the book&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-can-own-the-book&quot; aria-label=&quot;Anchor link for: one-can-own-the-book&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Each note, no matter what size it is, can have one owner. Me, you, anyone, it
doesn&#x27;t matter, but there will be only one owner. You can do whatever you want
with such note but with that power comes, not so great, responsibility: after
you are done with this book you will need to get rid of it. Since you are a law
abiding citizen you will recycle the note in the appropriate receptacle, but it
is your responsibility to do it. Of course this is not the only way to deal with
a note. You can also give it to someone and then it will be hers or his
responsibility.&lt;&#x2F;p&gt;
&lt;p&gt;To rephrase it in the Rust way, it would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Note&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; john&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Note&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; john creates the book and he owns it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; here he can do whatever he want with our `book`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; at the end of his life john will destroy all his belongings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; steve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Note&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; new book&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; he can do whatever he wants to do with his book&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    sally&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; steve gives the book to `sally`,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; Sally has the responsibility to destroy it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; now steve cannot do anything with this book,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; as it is not his personal belonging anymore&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;one-can-borrow-the-book&quot;&gt;One can borrow the book&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-can-borrow-the-book&quot; aria-label=&quot;Anchor link for: one-can-borrow-the-book&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;When we don&#x27;t want to give someone a book (we like that one), we can also lend
them one. And there are two ways to borrow one book:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;We can edit that book (ex. it is our personal dairy) and we lend it to someone
to check our spelling. We trust that person and we explicitly allow her to
edit our notes in place. We call it &lt;strong&gt;mutable borrow&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We do not trust someone and we lend our beloved book with no permission to edit
it. Even more, that person knows, that writing something in that book will
make us go rampage and destroy the whole universe. It will be an &lt;strong&gt;immutable
borrow&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course if we borrow something from someone else, then we can lend it further
with the same rules that were applied to us.&lt;&#x2F;p&gt;
&lt;p&gt;Rust also ensures that &lt;strong&gt;mutable borrow&lt;&#x2F;strong&gt; is unique. There will never be more
than one person that will be allowed to edit the book. We can still create a chain
of trust. Like when I find someone who is better at English than me, I would
allow this person to correct an article written by me or my friend who has
entrusted me with correcting his text.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Immutable borrows&lt;&#x2F;strong&gt; aren&#x27;t exclusive. I can lend my books as many times as I
want with one exception: I cannot lend a book that is still borrowed by someone
who can change its content.&lt;&#x2F;p&gt;
&lt;p&gt;In Rust it would look like that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; my&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Note&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    spelling_corrector&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-storage&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; we must explicitly mention that we lend the book&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; and we don&amp;#39;t give it away&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    reader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; spelling_corrector&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-storage&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Note&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; correct spelling in place&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; reader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Note&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; read a book&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;not-all-notes-are-worth-borrowing&quot;&gt;Not all notes are worth borrowing&lt;a class=&quot;zola-anchor&quot; href=&quot;#not-all-notes-are-worth-borrowing&quot; aria-label=&quot;Anchor link for: not-all-notes-are-worth-borrowing&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Sometimes this whole process of lending and then receiving a note back is much
more complicated than just cloning the whole note for someone else. Imagine that
you are in school and friend wants to copy your homework. What you do is lend
your homework to him, and with caution he can clone it on his own. This is what
Rust&#x27;s &lt;code&gt;Clone&lt;&#x2F;code&gt; trait provides - a method to clone content of struct without moving
its ownership.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-meta z-attribute&quot;&gt;#[derive(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; my&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    friend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; friend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;work&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; we lend it immutably&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Homework&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; work&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; your friend now has his own modifiable copy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But some notes are even shorter than that. They are so short and easy to clone
that it is much easier to clone them every time, instead of explicitly
calling the method. Like when you give your phone number to a hot girl at the
bar, the &lt;code&gt;Copy&lt;&#x2F;code&gt; trait automatically clones your note so the other has their own copy.
Again, this is for small types that can be mechanically copied each time when needed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-meta z-attribute&quot;&gt;#[derive(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Copy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; everything that is `Copy` must be also `Clone`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; PhoneNo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; my&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; no&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; PhoneNo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    hot_stuff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;no&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; hot_stuff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;no&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; PhoneNo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; fingers crossed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;There is more to learn, but these are the basic laws of ownership in Rust.
Everything else is based on this. If you understand this, it will become much
easier for you to understand how other types behave and, more importantly, why
they work the way they do.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
      <title>Dumb Elixir VIsual (and iMproved) editor</title>
      <published>2019-04-13T00:00:00+00:00</published>
      <updated>2019-04-13T00:00:00+00:00</updated>
      <link href="https://hauleth.dev/post/vim-for-elixir/" type="text/html"/>
      <id>https://hauleth.dev/post/vim-for-elixir/</id><summary>How I have configured Vim for working with Elixir and Erlang projects</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Earlier published on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@hauleth&#x2F;dumb-elixir-visual-and-improved-editor-53c23a0800e4&quot;&gt;Medium&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;vim-session.png&quot; alt=&quot;My example session in NeoVim with QuickFix displaying Credo warnings&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I am quite orthodox Vim user and I like to know everything that is happening in
my editor configuration. By no means I am &quot;minimal&quot; Vim user. I currently have
48 plugins installed, I just very carefully pick my plugins (few of them I have
written myself) to use only plugins that I understand and I can fix on my own in
case of problems. This results with configuration I understand and control in
all means.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-this-article-is-not&quot;&gt;What this article is not&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-this-article-is-not&quot; aria-label=&quot;Anchor link for: what-this-article-is-not&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This isn&#x27;t &quot;introduction into Vim&quot; article neither &quot;how to configure Vim for
Elixir development&quot;. Here I will try to describe how I use Vim for Elixir and
Erlang development. You can find some nice ideas and tips that may help you, but
by any means I do not mean that this is configuration you should or should not
use. You should use whatever you like (even if I do not like what you use) as
long as you understand what you use and why you use that.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Any sufficiently complicated set of Vim plugins contains an ad hoc,
informally-specified, bug-ridden, slow implementation of half of Vim&#x27;s
features.&lt;&#x2F;em&gt;
-- robertmeta&#x27;s tenth rule.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now we can start.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basics&quot;&gt;Basics&lt;a class=&quot;zola-anchor&quot; href=&quot;#basics&quot; aria-label=&quot;Anchor link for: basics&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I am using NeoVim 0.3.4, but almost everything I will describe there should work
in Vim 8.1+ as well. If you will encounter any problems, then please let me
know.&lt;&#x2F;p&gt;
&lt;p&gt;Vim doesn&#x27;t (as 13.04.2019) support Elixir out of the box, so what we
need is to install &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elixir-editors&#x2F;vim-elixir&quot;&gt;&lt;code&gt;vim-elixir&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; plugin which will provide niceties like syntax
colouring and indentation. Even if syntax colouring isn&#x27;t your thing then I
would still recommend installing it as it provides other things that it provides
few other niceties that I will describe later.&lt;&#x2F;p&gt;
&lt;p&gt;But how to install it? In truly minimal setup you can just create
&lt;code&gt;pack&#x2F;elixir&#x2F;start&lt;&#x2F;code&gt; directory within your &lt;code&gt;~&#x2F;.vim&lt;&#x2F;code&gt; folder
(&lt;code&gt;$XDG_CONFIG_DIR&#x2F;nvim&lt;&#x2F;code&gt; in case of NeoVim) and clone given repository there.
However, I am using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kristijanhusak&#x2F;vim-packager&quot;&gt;&lt;code&gt;vim-packager&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; which is based on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;k-takata&#x2F;minpac&quot;&gt;&lt;code&gt;minpac&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and is
truly minimal package manager (it is important distinction from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;junegunn&#x2F;vim-plug&quot;&gt;&lt;code&gt;vim-plug&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
or others that also manages plug-in loading. These plugins only manage fetching)
which even do not need to be loaded during &quot;normal&quot; runtime, only when you are
updating plugins.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-navigation&quot;&gt;Project navigation&lt;a class=&quot;zola-anchor&quot; href=&quot;#project-navigation&quot; aria-label=&quot;Anchor link for: project-navigation&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A lot of people, when come from other editors, often install NERDTree to have
&quot;project drawer&quot; functionality within Vim, because this is what they are used
to. Unfortunately &quot;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;vimcasts.org&#x2F;blog&#x2F;2013&#x2F;01&#x2F;oil-and-vinegar-split-windows-and-project-drawer&#x2F;&quot;&gt;split windows and the project drawer go together like oil
and vinegar&lt;&#x2F;a&gt;&quot; and it can result in painful experience or, which
is even worse, avoiding built-in functionalities, because these do not mix well.
Vim comes with built-in NetRW plugin for working with remote files and directory
tries. However for me this plugin is bloated as well and I would love to get rid
of it (unfortunately it is not currently possible as few functionalities relies
on it, namely dictionaries) so I replaced everything with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;justinmk&#x2F;vim-dirvish&quot;&gt;&lt;code&gt;dirvish&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
Additionally, I often use fuzzy finder, which in my case is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;srstevenson&#x2F;vim-picker&quot;&gt;&lt;code&gt;vim-picker&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; with
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jhawthorn&#x2F;fzy&quot;&gt;&lt;code&gt;fzy&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; which for me is much faster and more precise than popular FZF.&lt;&#x2F;p&gt;
&lt;p&gt;These tools are great when we are navigating in tree that is new to us or do not
have explicit structure. When we are working on Elixir projects then we know
before hand that there will be some commonly shared structure. Like
&lt;code&gt;lib&#x2F;&amp;lt;name&amp;gt;.ex&lt;&#x2F;code&gt; will contain source code, &lt;code&gt;test&#x2F;&amp;lt;name&amp;gt;_test.exs&lt;&#x2F;code&gt; will contain
test files, etc. What is more we know that &lt;code&gt;&amp;lt;name&amp;gt;&lt;&#x2F;code&gt; part will be shared between
file and its unit tests. This is very powerful assumption, as this allow us to
use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-projectionist&quot;&gt;&lt;code&gt;vim-projectionist&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; with ease. This plugin provide 3 main
functionalities (for me):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Jumping to the files basing on their path, so for example I can use &lt;code&gt;:Elib foo&lt;&#x2F;code&gt; to automatically jump to file &lt;code&gt;lib&#x2F;foo.ex&lt;&#x2F;code&gt;. It doesn&#x27;t seems like much,
but it also provides fuzzy finding, and allows me to define more specific
matches, like &lt;code&gt;:Econtroller foo&lt;&#x2F;code&gt; will open
&lt;code&gt;lib&#x2F;app_web&#x2F;controllers&#x2F;foo_controller.ex&lt;&#x2F;code&gt; (not exactly that as I use
different project layout, but that is topic on another article).&lt;&#x2F;li&gt;
&lt;li&gt;File templates, so when I start editing file (doesn&#x27;t matter how I opened it,
so this do not require to use above &lt;code&gt;:Elib&lt;&#x2F;code&gt; command), so when I start editing
test file it automatically add scaffold which I can configure per project.&lt;&#x2F;li&gt;
&lt;li&gt;Alternate files which in short are &quot;related&quot; files. For example when I edit
file &lt;code&gt;lib&#x2F;foo&#x2F;bar&#x2F;baz.ex&lt;&#x2F;code&gt; and I run &lt;code&gt;:A&lt;&#x2F;code&gt; it will create (if not exist) and
jump to the file &lt;code&gt;test&#x2F;foo&#x2F;bar&#x2F;baz_test.exs&lt;&#x2F;code&gt; which will be already scaffolded
by the earlier functionality. Recently it even became possible to have
multiple alternates.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Whole plugin is configured by &lt;code&gt;.projections.json&lt;&#x2F;code&gt; file, but it would be
infeasible to add this file to each project you work for. Fortunately there is
solution for that, we can define &quot;heuristics&quot; that will try to match for given
project structure and provide such features &quot;globally&quot;. My configuration for
that looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; g:projectionist_heuristics[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;mix.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;apps&#x2F;*&#x2F;mix.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;app&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;lib&#x2F;*.ex&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;lib&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;alternate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;test&#x2F;{}_test.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;template&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;defmodule {camelcase|capitalize|dot} do&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;end&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;test&#x2F;*_test.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;alternate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;lib&#x2F;{}.ex&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;template&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;defmodule {camelcase|capitalize|dot}Test do&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;  use ExUnit.Case&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;  alias {camelcase|capitalize|dot}, as: Subject&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;  doctest Subject&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;       &amp;#39;end&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt;   ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;mix.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;mix&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;config&#x2F;*.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;config&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;*.ex&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;makery&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     &amp;#39;lint&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;compiler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;credo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     &amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;compiler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;exunit&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     &amp;#39;build&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;compiler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;mix&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt;   }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;*.exs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;makery&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     &amp;#39;lint&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;compiler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;credo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     &amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;compiler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;exunit&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     &amp;#39;build&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;compiler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;mix&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt;   }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; g:projectionist_heuristics[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;rebar.config&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;*.erl&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;template&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;-module({basename}).&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;-export([]).&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;src&#x2F;*.app.src&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;app&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;src&#x2F;*.erl&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;src&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;alternate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;test&#x2F;{}_SUITE.erl&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;test&#x2F;*_SUITE.erl&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;   &amp;#39;alternate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;src&#x2F;{}.erl&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;rebar.config&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;rebar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;this-will-provide&quot;&gt;This will provide:&lt;a class=&quot;zola-anchor&quot; href=&quot;#this-will-provide&quot; aria-label=&quot;Anchor link for: this-will-provide&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;for-elixir&quot;&gt;For Elixir:&lt;a class=&quot;zola-anchor&quot; href=&quot;#for-elixir&quot; aria-label=&quot;Anchor link for: for-elixir&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lib&lt;&#x2F;code&gt; that will contain project source files which will be already filled with
module named &lt;code&gt;Foo.BarBaz&lt;&#x2F;code&gt; for file named &lt;code&gt;lib&#x2F;foo&#x2F;bar_baz.ex&lt;&#x2F;code&gt; (jump by &lt;code&gt;:Elib foo&#x2F;bar_baz&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;test&lt;&#x2F;code&gt; for test files which will be instantiated with module named
&lt;code&gt;Foo.BarBazTest&lt;&#x2F;code&gt; for file &lt;code&gt;test&#x2F;foo&#x2F;bar_baz_test.exs&lt;&#x2F;code&gt; that will already use
&lt;code&gt;ExUnit.Case&lt;&#x2F;code&gt; (you can jump via &lt;code&gt;:Etest foo&#x2F;bar_baz&lt;&#x2F;code&gt;), will define
&lt;code&gt;alias Foo.BarBaz, as: Subject&lt;&#x2F;code&gt;, and will run doctests for that module&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;config&lt;&#x2F;code&gt; for configuration files&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;mix&lt;&#x2F;code&gt; for &lt;code&gt;mix.exs&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It will also define test files as default alternates for each source file (and
vice versa, because alternate files do not need to be symmetric), so if you
run &lt;code&gt;:A&lt;&#x2F;code&gt; in file &lt;code&gt;lib&#x2F;foo&#x2F;bar_baz.ex&lt;&#x2F;code&gt; it will automatically jump to the
&lt;code&gt;test&#x2F;foo&#x2F;bar_baz_test.exs&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;for-erlang&quot;&gt;For Erlang:&lt;a class=&quot;zola-anchor&quot; href=&quot;#for-erlang&quot; aria-label=&quot;Anchor link for: for-erlang&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src&lt;&#x2F;code&gt; for source files&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;app&lt;&#x2F;code&gt; for &lt;code&gt;*.app.src&lt;&#x2F;code&gt; files&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;test&lt;&#x2F;code&gt; for common test suites&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;rebar&lt;&#x2F;code&gt; for &lt;code&gt;rebar.config&lt;&#x2F;code&gt; file&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The relation between source files and test files is exactly the same as in
Elixir projects.&lt;&#x2F;p&gt;
&lt;p&gt;One thing can bring your attention, why the hell I define helpers for &lt;code&gt;mix.exs&lt;&#x2F;code&gt;
and &lt;code&gt;rebar.config&lt;&#x2F;code&gt; as you can simply use &lt;code&gt;:e &amp;lt;file&amp;gt;&lt;&#x2F;code&gt;. The answer is simple, &lt;code&gt;:e&lt;&#x2F;code&gt;
will work for files in Vim working directory while &lt;code&gt;:E&lt;&#x2F;code&gt; will work form the
projectionist root, aka directory where is &lt;code&gt;.projections.json&lt;&#x2F;code&gt; file defined (or
in case of heuristics, from the directory that matched files). This mean that
when I edit files in umbrella application I can use &lt;code&gt;:Emix&lt;&#x2F;code&gt; (or &lt;code&gt;:Erebar&lt;&#x2F;code&gt;) to
edit current sub-project config file and &lt;code&gt;:e mix.exs&lt;&#x2F;code&gt; to edit global one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;completion-and-language-server&quot;&gt;Completion and language server&lt;a class=&quot;zola-anchor&quot; href=&quot;#completion-and-language-server&quot; aria-label=&quot;Anchor link for: completion-and-language-server&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;For completion and code formatting I use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;prabirshrestha&#x2F;vim-lsp&quot;&gt;&lt;code&gt;vim-lsp&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. I have tried most of the
language server clients out there, but I always come back to this one for a few
reasons:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It is implemented only in VimL which mean that I am not forced to installing
any compatibility layers or fighting with different runtimes.&lt;&#x2F;li&gt;
&lt;li&gt;It is simple enough that I can easily dig into it, and fix problems that I
have encountered.&lt;&#x2F;li&gt;
&lt;li&gt;It doesn&#x27;t override any built-in Vim functionality and instead provide set of
commands that you can then bind to whatever mappings you want.&lt;&#x2F;li&gt;
&lt;li&gt;It do not force me to use autocompletion, which I do not use at all. At the
same time it provides seamless integration with built-in Vim functionality of
omnicompletion and user completion by providing &lt;code&gt;lsp#complete&lt;&#x2F;code&gt; function.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This approach of not providing default mappings is really nice for power users,
as this allow us to define everything on our own. For example, some of plugins
use &lt;kbd&gt;&amp;lt;C-]&amp;gt;&lt;&#x2F;kbd&gt; for jumping to definition, which I often use (it is
jump to tag definition) and shadowing it would be problematic for me. So in the
end I have created my own set of mappings, that have additional feature of being
present only if there is any server that supports them:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-keyword z-operator&quot;&gt;func!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; s:setup_ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; abort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:servers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; lsp#get_whitelisted_servers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:server&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:servers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; l:cap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; lsp#get_server_capabilities&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; has_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;completionProvider&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;            setlocal&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; omnifunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;lsp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;complete&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; has_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;hoverProvider&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;            setlocal&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; keywordprg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;:LspHover&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; has_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;definitionProvider&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;            nmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;silent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;buffer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; gd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;lsp&lt;&#x2F;span&gt;&lt;span&gt;-definition&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; has_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;l:cap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;referencesProvider&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;            nmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;silent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;buffer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; gr &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;plug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;lsp&lt;&#x2F;span&gt;&lt;span&gt;-references&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    endfor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;endfunc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;augroup&lt;&#x2F;span&gt;&lt;span&gt; LSC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-keyword z-operator&quot;&gt;    autocmd!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    autocmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; lsp_setup &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; lsp#register_server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;name&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;ElixirLS&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;cmd&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {_-&amp;gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;elixir-ls&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;whitelist&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;elixir&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;eelixir&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    autocmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; lsp_setup &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; lsp#register_server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;name&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;RLS&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;cmd&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {_-&amp;gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;rls&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;whitelist&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;rust&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    autocmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; lsp_setup &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; lsp#register_server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;name&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;solargraph&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;cmd&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {server_info-&amp;gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;solargraph&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;stdio&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;initialization_options&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;diagnostics&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;true&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;whitelist&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;ruby&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    autocmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; lsp_setup &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; lsp#register_server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;name&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;dot&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;cmd&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {server_info-&amp;gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;dot-language-server&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;--stdio&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;whitelist&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;dot&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                \&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    autocmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; lsp_server_init &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;SID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;setup_ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    autocmd&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt; BufEnter&lt;&#x2F;span&gt;&lt;span&gt; * &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;call&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character&quot;&gt;SID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;setup_ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;augroup&lt;&#x2F;span&gt;&lt;span&gt; END&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;running-tasks-and-linting&quot;&gt;Running tasks and linting&lt;a class=&quot;zola-anchor&quot; href=&quot;#running-tasks-and-linting&quot; aria-label=&quot;Anchor link for: running-tasks-and-linting&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A lot of people &quot;cannot live&quot; without lint-as-you-type feature, but I think,
that not using such functionality makes me a less sloppy and better programmer.
It makes me to think when I write and do not rely on some magical friend that
will always watch over my shoulder. However when the problem happens in my code
I would like to know where and quickly jump to the place where error occurred.
Additionally, I would like to run tasks in the background without interruption
to my current work. All of it became possible with introduction of asynchronous
tasks in NeoVim and Vim 8. So I have created plugin &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hauleth&#x2F;asyncdo.vim&quot;&gt;&lt;code&gt;asyncdo.vim&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; that
allows me to easily implement &lt;code&gt;:Make&lt;&#x2F;code&gt; command that works exactly like
built-in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;quickfix.txt.html#%3Amake&quot;&gt;&lt;code&gt;:make&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, but do not halt my normal work. Together with
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;igemnace&#x2F;vim-makery&quot;&gt;&lt;code&gt;vim-makery&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (which nicely integrates with &lt;code&gt;vim-projectionsit&lt;&#x2F;code&gt;) and built-in
functionality of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimhelp.org&#x2F;quickfix.txt.html#%3Acompiler&quot;&gt;&lt;code&gt;:compiler&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which is supported by &lt;code&gt;vim-elixir&lt;&#x2F;code&gt;, it allows
me to easily run all sorts of commands very easily. If you look into
projectionist heuristics above you will see that there is &lt;code&gt;&quot;makery&quot;&lt;&#x2F;code&gt; key defined
for &lt;code&gt;*.ex&lt;&#x2F;code&gt; and &lt;code&gt;*.exs&lt;&#x2F;code&gt; files. That allows me to run &lt;code&gt;:Mlint %&lt;&#x2F;code&gt; to run Credo on
current file and the results will be present within QuickFix window which
together with my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;hauleth&#x2F;qfx.vim&quot;&gt;&lt;code&gt;qfx.vim&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; will mark lines with errors using signs. In the
same manner I can run &lt;code&gt;:Mtest&lt;&#x2F;code&gt; to run tests for whole project and have failed
tasks visible in QuickFix window.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-utilities&quot;&gt;Other utilities&lt;a class=&quot;zola-anchor&quot; href=&quot;#other-utilities&quot; aria-label=&quot;Anchor link for: other-utilities&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;There is bunch of other plugins that are quite helpful when it comes to working
on Elixir projects and do not interfere with Vim features, ex.:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-dadbod&quot;&gt;&lt;code&gt;vim-dadbod&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; which allows you to run SQL queries from within Vim, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elixir-editors&#x2F;vim-elixir&#x2F;pull&#x2F;481&quot;&gt;I
have written integration with Ecto&lt;&#x2F;a&gt; which is provided with
&lt;code&gt;vim-elixir&lt;&#x2F;code&gt; by default. So if you are working on Elixir application that has
&lt;code&gt;MyApp.Repo&lt;&#x2F;code&gt; Ecto repository then you can run &lt;code&gt;:DB MyApp.Repo&lt;&#x2F;code&gt; and Vim will
open your DB client within separate terminal that will be connected to your DB&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-endwise&quot;&gt;&lt;code&gt;vim-endwise&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; that will automatically add end to your do blocks&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;direnv&#x2F;direnv.vim&quot;&gt;&lt;code&gt;direnv.vim&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; simplify management of environment variables in per-directory
manner&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sgur&#x2F;vim-editorconfig&quot;&gt;&lt;code&gt;vim-editorconfig&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sgur&quot;&gt;sgur&lt;&#x2F;a&gt;&#x27;s one, not official one) - pure VimL support
for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;editorconfig.org&quot;&gt;EditorConfig&lt;&#x2F;a&gt; files&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I hope that you find some nice ideas within this article that will help in
improving your own Vim configuration without adding much clutter.&lt;&#x2F;p&gt;
&lt;p&gt;No, I will not publish my own &lt;code&gt;vimrc&lt;&#x2F;code&gt; in fear that some of you will copy it as
is (also not that this is particularly troublesome for anyone who is aware of
Google to find it). Instead, I highly suggest You to dig into your own
configuration and for each line ask yourself:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Do I know what this line &lt;strong&gt;does&lt;&#x2F;strong&gt;?&lt;&#x2F;li&gt;
&lt;li&gt;Do I really &lt;strong&gt;need&lt;&#x2F;strong&gt; this line?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And if answer for any of these questions is &lt;strong&gt;no&lt;&#x2F;strong&gt; then remove such line. In the
end you either learn what for it was, or that you never needed it.&lt;&#x2F;p&gt;
</content>
    </entry>
</feed>
