<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/assets/rss.xsl"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Domenico Luciani</title>
    <link>https://domenicoluciani.com</link>
    <description>Thoughts about life, tech and everything</description>
    <language>en</language>
    <lastBuildDate>Wed, 13 May 2026 23:41:44 +0200</lastBuildDate>
    <atom:link href="https://domenicoluciani.com/feed.xml" rel="self" type="application/rss+xml" /><item>
      <title>LFS148: Getting Started with OpenTelemetry</title>
      <link>https://domenicoluciani.com/2025/11/29/getting-started-with-open-telemetry.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2025/11/29/getting-started-with-open-telemetry.html</guid>
      <pubDate>Sat, 29 Nov 2025 00:00:00 +0100</pubDate><description>Want to dive-in into OpenTelemetry? This course is for you</description>
      <content:encoded><![CDATA[
<p>At wortk I’m currently leading an observability initiative using <a href="https://opentelemetry.io/">OpenTelemetry</a>, since I’m a very curious person I decided to take part of a small course provided by <a href="https://training.linuxfoundation.org/">the Linux Foundation</a>, <strong>FOR FREE</strong> 💰.</p>

<div data-iframe-width="500" data-iframe-height="300" data-share-badge-id="1994419e-d207-4b2b-a3c2-78e770548f86" data-share-badge-host="https://www.credly.com"></div>
<script type="text/javascript" async="" src="//cdn.credly.com/assets/utilities/embed.js"></script>

<p>The course was really interesting, it gave me a panoramic view of the OpenTelemetry internals, and how they work. In the course there was an hands-on part, where I could see OTel in action, seeing how OTel can be integrated with some Java and Python applications. No rocket-science tho, this course is a basic course but in my opinion it’s really worth it, if you want to start working with OTel and c’mon, it’s free!</p>

      ]]></content:encoded>
    </item><item>
      <title>The Physics of Software Development</title>
      <link>https://domenicoluciani.com/2025/11/14/the-physics-of-software-development.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2025/11/14/the-physics-of-software-development.html</guid>
      <pubDate>Fri, 14 Nov 2025 00:00:00 +0100</pubDate><description>As a software engineer let&apos;s use a tool to discuss with business and get out from there like a boss would do.</description>
      <content:encoded><![CDATA[
<p>As a software engineer, negotiating with the business can be tricky and sometimes stressful, especially without the right tools. So, today, I’d like to discuss a specific tool that helped me escape endless business meetings, and yet almost never gets mentioned in them.</p>

<h2 id="the-physics-of-software-development">The Physics of Software Development</h2>

<p>Lots of business people don’t even know that behind a software project, there are actual physical laws that need to be respected to avoid ending up in situations far from reality, introducing wrong expectations, and catastrophic results.</p>

<h3 id="the-software-project-triangle">The Software Project Triangle</h3>

<p><img src="/assets/images/posts/software_project_triangle.png" alt="software-project-triangle" /></p>

<p>There is a very simple rule for interpreting this triangle:</p>

<blockquote class="callout warn">
  <p><strong>Important</strong>
If one of these components changes, at least one of the others needs to change.</p>
</blockquote>

<h2 id="people-decrease">People decrease</h2>

<p>If, for whatever reason, <strong>the number of people working on a project decreases</strong>, <strong>the scope needs to be reduced and/or the timeline increased</strong>.</p>

<p><img src="/assets/images/posts/less_people_more_scope_more_timeline.png" alt="less-people-more-scope-and-timeline" /></p>

<p>Some people may push the team to work extra hours, until they realize that <strong>a tired developer is likely to introduce more bugs than a fresh one</strong>, and I don’t even want to talk about burning those people out and <strong>eventually end up with fewer people than when you started</strong>.</p>

<h2 id="scope-increases">Scope increases</h2>

<p>Too often I see businesses wanting to increase the scope in the middle of the project because “our priorities changed”, not respecting the physics of software development.</p>

<p>I’m sorry, Mr. Businessman, but if you <strong>increase the scope,</strong> then <strong>the timeline and/or the number of people must also increase</strong> to keep things working fine.</p>

<p><img src="/assets/images/posts/more_people_timeline_scope.png" alt="more-people-more-scope-and-timeline" /></p>

<h2 id="timeline-decrease">Timeline decrease</h2>

<p>If the <strong>timeline deadline is moved closer</strong>, then <strong>the scope needs to be decreased</strong>.
What we often see in this situation is that people will work more hours, increasing the “people” variable.</p>

<p><img src="/assets/images/posts/less_timeline_less_scope_more_people.png" alt="less_timeline_less_scope_more_people" /></p>

<p>But be careful with that, because the <a href="/2025/11/14/software-project-physics.html#adding-people">adding people</a> parenthesis is still valid, <strong>making people work more hours can introduce bugs and make them less efficient and productive</strong>.</p>

<h3 id="adding-people">Adding people</h3>

<p>I want to add a side note on the “adding more people” concept since this is not very clear for many. When we add a new person to an ongoing project, <strong>that person needs to be onboarded</strong>, and <strong>it requires time</strong>, time that will reduce the original planned timeline, time that hasn’t been taken into consideration at the beginning of the project.</p>

<p>True, some projects can have tasks that can be parallelized or require very little onboarding, and in those cases it can definitely improve the timeline, but this always involves hard tradeoffs in onboarding time.</p>

<p>So no, doubling the number of engineers <strong>won’t</strong> cut the time to completion in half, but if they have domain knowledge and the work can be split up enough, then it can reduce the timeline if done carefully.</p>

<hr />

<p>So next time the business wants to change any of these variables without adjusting the others, remembering this principle will help you avoid paying the price in delays, bugs, frustration, or burnout.</p>

      ]]></content:encoded>
    </item><item>
      <title>You are doing your team retrospective wrong</title>
      <link>https://domenicoluciani.com/2025/11/03/you-are-doing-your-team-retrospective-wrong.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2025/11/03/you-are-doing-your-team-retrospective-wrong.html</guid>
      <pubDate>Mon, 03 Nov 2025 00:00:00 +0100</pubDate><description>A team retrospective is not just another useless meeting, and if you feel so, it means you are doing it wrong, and this article is for you.</description>
      <content:encoded><![CDATA[
<p>A team retrospective is not just another useless meeting, if it feels that way to you, it probably means you’re doing it wrong; and this article is for you.</p>

<p>With more than 10 years of experience as a Software Engineer, I’ve had the opportunity to attend hundreds of team retrospectives, and let me tell you: it’s the most valuable meeting a team can have, <em>if you know how to do it properly.</em> 😏</p>

<hr />

<h2 id="why-is-it-important-">Why is it important? 🎩</h2>

<p>A retrospective is when a team can learn from its own mistakes, share gratitude, ask for help, celebrate and talk about new ideas. Do you already see the potential? 📈</p>

<h3 id="self-improvement-">Self-improvement 🔁</h3>

<p>Do you see something in the team that could be improved or is slowing you down? 
Raise your hand. 🙋‍♂️</p>

<h3 id="what-if-">“What if?” 🤔</h3>

<p>Do you have a new idea? Do you want to try something new, and want to get the team’s opinion on it? Go for it!</p>

<h3 id="celebration-">Celebration!! 🥳</h3>

<p>Did your team achieve something, or do you want to say thank you to a specific person that helped you out? (<em>making it in public is better 😉</em>)</p>

<h3 id="reflection-">Reflection 🙅</h3>

<p>The power of this ceremony lies in encouraging the team to reflect on past events like what went wrong, or what could have been better.</p>

<blockquote class="callout warn">
  <p><strong>Important</strong>
It is about continuous improvement, <strong>not blaming</strong>. 🙅🏻</p>
</blockquote>

<p>In a safe environment we should aim to point our fingers at processes that didn’t work, <strong>not at people</strong>.</p>

<h2 id="team-psychological-safety">Team Psychological Safety</h2>

<blockquote class="callout warn">
  <p><strong>Important</strong>
Psychological safety is a very important thing to have in your team, the aim is to make the people feeling safe. This should be your top priority, the sooner you have it in your team, the better.</p>
</blockquote>

<p>Having people in the team who feel safe is one of the most important aspects of healthy team dynamics. A team that feels safe, will be transparent, honest, and they will take risks. 
During a retro, you want people to have the courage to speak up and address issues by discussing solutions and ideas. You want your team not to be afraid of saying “we should stop this” or “this is not working for us”. Without psychological safety, we can’t have all the benefits we mentioned earlier. If people don’t feel safe, your retrospective simply won’t work. I’m not going to cover this topic here, but you can definitely have a look at some articles online like:</p>
<ul>
  <li><a href="https://www.thoughtworks.com/insights/blog/product-innovation/psychological-safety-product-innovation">https://www.thoughtworks.com/insights/blog/product-innovation/psychological-safety-product-innovation</a></li>
  <li><a href="https://www.ccl.org/articles/leading-effectively-articles/what-is-psychological-safety-at-work/">https://www.ccl.org/articles/leading-effectively-articles/what-is-psychological-safety-at-work/</a></li>
  <li><a href="https://psychsafety.com/about-psychological-safety/">https://psychsafety.com/about-psychological-safety/</a></li>
</ul>

<h2 id="format-">Format 👾</h2>

<p>Many people I’ve talked with believe there’s only one effective retrospective format</p>

<p><img src="/assets/images/posts/retro_default.png" alt="retro-default" /></p>

<p>Which is completely false, changing retrospective format depending on your team situation <strong>is crucial</strong> to get the most out of this ceremony.</p>

<p>Retros should be fun and effective. Not all sprints or quarters look the same; so why should your retro?</p>

<h3 id="different-formats">Different formats?</h3>

<p>There are lots of templates online that can be used, my favorites can be found here:</p>
<ul>
  <li><a href="https://app.funretrospectives.com/new/custom-session">Fun Retrospectives</a>.</li>
  <li><a href="https://www.neatro.io/retrospective-templates/">Neatro Retro templates</a></li>
</ul>

<h3 id="setup">Setup</h3>

<p>Let’s pick as an example <a href="https://www.funretrospectives.com/the-good-the-bad-and-the-ugly/">“The good, the bad and the ugly” </a> retro format.</p>

<p>Set up three columns respectively with</p>
<ul>
  <li>The good 👍🏻</li>
  <li>The bad 🙅🏻</li>
  <li>The ugly 👹</li>
</ul>

<h3 id="old-action-items-">Old action items 📜</h3>

<p>Before starting the retro, spend some time reviewing the action items created in the last retro. Get updates on them, always remember to have them assigned to someone and add them to the next sprint.</p>

<h3 id="lets-start-️">Let’s start ⏲️</h3>

<p>In this phase the team can start creating stickies on the board.</p>

<p><img src="/assets/images/posts/good_bad_ugly.png" alt="good-bad-ugly" /></p>

<p>Each sticky should be in the appropriate column.</p>
<ul>
  <li><strong>The good</strong>: things that went well, and we should repeat, and do more of it.</li>
  <li><strong>The bad</strong>: things that should have never happened, and we must get rid of it.</li>
  <li><strong>The ugly</strong>: things that did not go so well, and we should look for improvements, turning them into something better.</li>
</ul>

<p>Write each one so the team can easily understand its context at a glance:</p>

<ul>
  <li>❌:  “Our process doesn’t work for me”</li>
  <li>✅: “The code review process is complicated and difficult to follow”</li>
  <li>❌: “Lack of privileges”</li>
  <li>✅: “Couldn’t do the migration due to lack of privileges.”</li>
</ul>

<p><em>This activity should last around 3–5 minutes. If the team isn’t very active, wrap it up earlier; if they’re engaged, give them an extra minute or two.</em></p>

<h3 id="clarification-and-grouping-️">Clarification and grouping 🏘️</h3>

<p>In this phase the whole team reviews the stickies and clarify them if necessary, and start grouping similar stickies together.
Something that works well for me is drawing a large square to summarize each group of related stickies, like in the image</p>

<p><img src="/assets/images/posts/retro_grouping.png" alt="retro-grouping" /></p>

<h3 id="voting-️">Voting 🗳️</h3>

<p>Now it’s time to vote, each member of the team should have 2 or 3 votes, and votes should be anonymous.</p>

<p>If there is a group of stickies, votes go on the main group label, otherwise they go on the single sticky.</p>

<p><em>This activity should last between 3 and 5 minutes, nowadays most tools show when everyone has voted, or you can say to your team members to raise their hand on your call to mark that they have voted.</em></p>

<p>After that you can show the voting results.</p>

<h3 id="discussion-️">Discussion 🎙️</h3>

<p>Pick the sticky (or group) with the highest number of votes, and set 10 minutes for the discussion.</p>

<p>The aim of the conversation is to explore what happened, and address it through the creation of action items.</p>

<p>After timing out, the team can decide if they want to continue for 5 more minutes or stop. Repeat until the team is satisfied and there are action items for that specific topic.</p>

<p>The conversation should be started by the author, and the team should follow up the conversation, adding insights and thoughts.</p>

<blockquote class="callout warn">
  <p><strong>Important</strong>
 If there are 5 votes, at least two or three people should be talking and adding something to the conversation; having just one person talking it’s not a conversation, it’s a monologue. 🙅🏻</p>
</blockquote>

<h3 id="action-items-">Action Items 🪧</h3>

<p>As introduced above, action items are produced by the team to address their issues, they should be <a href="https://www.atlassian.com/blog/productivity/how-to-write-smart-goals">S.M.A.R.T.</a>:</p>
<ul>
  <li>Specific</li>
  <li>Measurable</li>
  <li>Achievable</li>
  <li>Relevant</li>
  <li>Time-Bound</li>
</ul>

<p>Assign each action item to an owner that will be accountable for it to be executed during the following sprint.</p>

<blockquote class="callout warn">
  <p><strong>Important</strong>
Adding an action item to the backlog and leaving it there won’t solve the issue, solving the issue will solve the issue. 🤯</p>
</blockquote>

<h3 id="round-of-kudos-and-positive-things--">Round of Kudos and positive things 👏🏻 🎉</h3>

<p>Before closing the meeting, spend some time reviewing kudos and positive stickies, to end the retro on a good note. 🧘🏻</p>

<hr />

<h2 id="common-pitfalls-">Common Pitfalls 👎🏻</h2>

<h3 id="team-members-become-spectators-">Team members become spectators 🥱❌</h3>

<p>When retrospectives are always facilitated by the same person (usually the tech lead or manager), the outcome tends to be the same every time: the team tends to get used to it, and the retro becomes “another meeting that could have been an email”. Team members become spectators. Instead of feeling that this ceremony is <strong>for them</strong>, they start seeing it as someone else’s responsibility.</p>

<blockquote class="callout error">
  <p><strong>Problem: Always the same person facilitating the retro 🙅🏼‍♂️</strong> 
Usually the tech lead or the manager facilitates the retro, leaving the team out of this duty.</p>
</blockquote>

<blockquote class="callout success">
  <p><strong>Solution: Rotate 🔁</strong> 
Rotate the facilitator every 1/2/4 weeks, make the people responsible for facilitating the retro correctly and efficiently. Give them feedback about how to improve it.</p>
</blockquote>

<blockquote class="callout info">
  <p><strong>Tip: Automatic rotation 🤖</strong> 
Add an automatic bot to rotate the person who takes the facilitator role for a specific time-window.</p>
</blockquote>

<h3 id="hearing-always-the-same-voice-️">Hearing always the same voice 🎙️❌</h3>

<p>Common scenario, have a sticky with lots of votes, but we hear just one or two people talking for the whole (time-boxed) time. Generally, if a sticky has a lot of votes, it means several people in the team care about the topic and have something to say. My advice is to let the author start, and then call out someone else who added a vote to it.</p>

<blockquote class="callout info">
  <p><strong>Question: Anybody else?</strong> 
Does anybody want to add anything? Can we hear another opinion? Thoughts?</p>
</blockquote>

<p>Different people might have different reasons to vote a specific sticky and some people are more silent than others, the benefit of doing this might be:</p>
<ol>
  <li>We hear what the owner has to say</li>
  <li>Hear others’ opinions (they vote it, they have at least one opinion about that topic)</li>
  <li>Keep people engaged.</li>
</ol>

<blockquote class="callout error">
  <p><strong>Problem: Cards with lots of votes being tackled by a single person 🙅🏼‍♂️</strong> 
We have only one voice in the room.</p>
</blockquote>

<blockquote class="callout success">
  <p><strong>Solution:  Let other people speak 🗣️</strong>
Don’t let the author of the sticky be the only one who gives an opinion, ask the rest of the team who voted the card to speak up and add more about the topic the team wants to talk about.</p>
</blockquote>

<blockquote class="callout info">
  <p><strong>Tip: Involve silent people</strong> 
Try to involve people who didn’t talk during the whole meeting, <strong>but don’t force them to do so</strong>.</p>
</blockquote>

<h3 id="not-time-boxing-">Not time-boxing 🍅</h3>

<p>As a facilitator the timer is your best friend, it is your duty to keep the meeting rolling and on-time, making sure that the important topics are discussed and that some action items have been created. To do so, you need to have time-boxed discussions.
Whenever a discussion starts let’s set 10 minutes to talk through the topic, if at the end of those 10 minutes the team is satisfied you can move on, otherwise just ask about adding up 5 minutes more.</p>

<blockquote class="callout info">
  <p><strong>Question: What now?</strong> 
Shall we spend 5 more minutes on this topic or move on?</p>
</blockquote>

<p>Do it just once, and focus on finding an action item, then move to the following topic, it brings lots of overlooked benefits:</p>
<ol>
  <li>Force the team to focus on what really matters</li>
  <li>Keep the timing under control</li>
  <li>It allows tackling more important topics</li>
</ol>

<blockquote class="callout error">
  <p><strong>Problem: Spending too much time on a single topic</strong> 
Spending most of our precious time talking just about one or two topics for the whole meeting</p>
</blockquote>

<blockquote class="callout success">
  <p><strong>Solution: Time-box discussions 🍅</strong> 
Set 10 minutes for each topic conversation, the aim is to find an action item.
If 10 minutes are not enough, ask the team if they want to talk about the topic for 5 more minutes or if they are okay with the outcome.</p>
</blockquote>

<blockquote class="callout info">
  <p><strong>Tip: Shared timers</strong> 
Try to use a timer that is visually shared with the team, (or just share your screen) so everybody is aware of the timing.</p>
</blockquote>

<h3 id="public-voting-">Public voting 🃏</h3>

<p>Some people in the team have more influence than others, and this can easily harm a retro meeting. Within a team there are multiple dynamics, and we have always to remember that those dynamics influence how we interact and work with each other.
So, to avoid having this hidden influence within our meeting, voting should be anonymous.</p>

<h3 id="only-one-person-doing-the-grouping-️">Only one person doing the grouping 🏘️❌</h3>

<p>Grouping helps the team to clarify the stickies and to come up with something that everybody understand and can vote, don’t let one person doing the dirty job when the rest of the team just stay still, involve them into the process, ask questions and how to name things. Make them part of the process.</p>

<h3 id="talk-about-every-single-sticky-on-the-board-">Talk about every single sticky on the board 😴❌</h3>

<p>Voting helps to prioritize what really matters for the team, and those stickies should be discussed before the end of the meeting.
If more stuff can be discussed go for it, but it’s not something you should tackle, especially if the retro runs over time.
Take those stickies into consideration and move on, closing the retro.</p>

<blockquote class="callout error">
  <p><strong>Problem: We ran out of time</strong> 
 We talked about less important stuff. The team lost interest.</p>
</blockquote>

<blockquote class="callout success">
  <p><strong>Solution: Pick the top 3 stickies</strong> 
 Pick the first 3 most voted topics and discuss them, it should be enough to tackle the important stuff. Close the meeting whenever you are done with them.</p>
</blockquote>

<h3 id="postponing-the-retro-because-we-are-too-busy-">Postponing the retro because “we are too busy” 📉❌</h3>

<p>Seriously, <strong>don’t</strong>. The retro it’s one of those meetings that if run well can help your team to move faster. ⚡️
A busy team can overlook important things that in that specific moment are making the team itself slower or less efficient. Reflecting over the sprint the team just had can make more evident what is not working, especially if the team needs to be fast.</p>

<blockquote class="callout warn">
  <p><strong>Example 🏎️</strong>
During a car race, if you have a flat tire, 
don’t you change it because you don’t have the time to address it?</p>
</blockquote>

<h3 id="waiting-for-the-teamtech-lead-to-have-a-retro-">Waiting for the team/tech lead to have a retro 🪫❌</h3>

<p>The retro is for the whole team, not for single individuals and the team shouldn’t wait for anybody to run it. Action items are assigned to team members, making them accountable for resolving them.</p>

<blockquote class="callout error">
  <p><strong>Problem: Only the tech/team lead can solve the issue ✋🏻</strong>
Can be that some issues can’t be solved by individual contributors, so what’s the point to have a retro if we can’t do anything about it?</p>
</blockquote>

<blockquote class="callout success">
  <p><strong>Solution: Have action items 📝</strong>
The team can always discuss the issue, create action items about it and assign the tech/team lead to follow up offline or whenever that person is back.</p>
</blockquote>

<h3 id="no-product-people-in-your-retro-️-">No product people in your retro ☎️ ❌</h3>

<p>In some companies product and engineering teams are two separate entitites which collaborate here and there, but never share a strong communication funnel. So what I’ve been seeing is engineering teams complaining about product people that never receive that feedback promptly or with the right context.</p>

<blockquote class="callout error">
  <p><strong>Problem: Broken feedback loop ⛓️‍💥</strong>
Product people are not participating to the retro.
Most of the engineers think that the retro would be too technical for product people, and product people think that they can’t provide any value to the engineering team conversations.</p>
</blockquote>

<p>What worked very well in my experience, is involving them to the team retros, starting with just once per month and then increase the attendances according to the feedback.</p>

<blockquote class="callout success">
  <p><strong>Solution: Retros all together 🔗</strong>
Start involving product people in the engineering team retros, start small and then increase the frequency if it is needed.</p>
</blockquote>

<p>I’ve seen product people become more aware of team issues and their surroundings. Engineering teams felt more heard by the people they were supposed to be collaborating with.
Thanks to the faster feedback loop, everyone felt that collaboration improved by an order of magnitude, understanding better the reasons behind certain decisions and processes that were affecting the team.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I hope that these tips help you understand how you can make the most out of the retro and why you should care about having it in your team as well.</p>

<blockquote class="callout warn">
  <p><strong>I’m just an engineer: I’m not a good faciliator! 🙋‍♂️</strong>
Facilitation is like a muscle, the more you practice it, the stronger it gets. And think about it, AI can’t do it. 😏</p>
</blockquote>

<p>Next time you have your retro, apply one of these ideas, and you’ll see how fast a good conversation can transform your team. 🤞🏻</p>

<p>Until next time! 👋🏻</p>

      ]]></content:encoded>
    </item><item>
      <title>How to use  generics to avoid duplications and make your code better</title>
      <link>https://domenicoluciani.com/2025/04/11/how-to-use-generics-to-avoid-duplications-and-make-your-code-better.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2025/04/11/how-to-use-generics-to-avoid-duplications-and-make-your-code-better.html</guid>
      <pubDate>Fri, 11 Apr 2025 00:00:00 +0200</pubDate><description>I recently worked on a project that had a lot of code duplication due to repeated implementations of the same interfaces. I quickly realized it was a great opportunity to refactor…</description>
      <content:encoded><![CDATA[
<p>I recently worked on a project that had a lot of code duplication due to repeated implementations of the same interfaces. I quickly realized it was a great opportunity to refactor the code, remove the duplication and make the code more scalable and maintainable.</p>

<hr />

<h2 id="initial-situation">Initial situation</h2>

<p>Implementing external interfaces is quite common in Go projects, but sometimes we have the necessity to implement those interfaces multiple times with different struct, ending up having lots of structs implementing the same methods without really having a different behavior in place.</p>

<p>For example, we can have something like this into an external dependency, let’s say something that helps us to return a particular response having a particular format:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c">//External dependency, living in an external project</span>
<span class="k">type</span> <span class="n">JSONResponse</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Name</span><span class="p">()</span> <span class="kt">string</span>
    <span class="n">GetSomething</span><span class="p">()</span> <span class="n">SomeThing</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And then, we have in our code:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">TypeOneResponse</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="o">...</span>
<span class="p">}</span>


<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">TypeOneResponse</span><span class="p">)</span> <span class="n">Name</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span> <span class="k">return</span> <span class="n">r</span><span class="o">.</span><span class="n">Name</span> <span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">TypeOneResponse</span><span class="p">)</span> <span class="n">GetSomething</span><span class="p">()</span> <span class="n">SomeThing</span> <span class="p">{</span> <span class="o">..</span><span class="n">logic</span> <span class="n">to</span> <span class="k">return</span> <span class="n">something</span><span class="o">..</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now let’s imagine that we have to implement it for all our responses, we are going to have:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">TypeOneResponse</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="o">...</span>
<span class="p">}</span>


<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">TypeOneResponse</span><span class="p">)</span> <span class="n">Name</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span> <span class="k">return</span> <span class="n">r</span><span class="o">.</span><span class="n">Name</span> <span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">TypeOneResponse</span><span class="p">)</span> <span class="n">GetSomething</span><span class="p">()</span> <span class="n">SomeThing</span> <span class="p">{</span> <span class="o">..</span><span class="n">logic</span> <span class="n">to</span> <span class="k">return</span> <span class="n">something</span><span class="o">..</span> <span class="p">}</span>


<span class="k">type</span> <span class="n">TypeTwoResponse</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="o">...</span>
<span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">TypeTwoResponse</span><span class="p">)</span> <span class="n">Name</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span> <span class="k">return</span> <span class="n">r</span><span class="o">.</span><span class="n">Name</span> <span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">TypeTwoResponse</span><span class="p">)</span> <span class="n">GetSomething</span><span class="p">()</span> <span class="n">SomeThing</span> <span class="p">{</span> <span class="o">..</span><span class="n">logic</span> <span class="n">to</span> <span class="k">return</span> <span class="n">something</span><span class="o">..</span> <span class="p">}</span>

<span class="o">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In no time we are going to have hundreds of lines of code that are just duplicated. Not nice, right?</p>

<h2 id="generics-to-the-rescue">Generics to the rescue</h2>

<p>Luckily Go introduced <a href="https://go.dev/doc/tutorial/generics">Generics</a>, which helps us to solve the problem.</p>

<p>Let’s define a new common and generic struct:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Response</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Name</span> <span class="kt">string</span>
    <span class="n">Payload</span> <span class="n">T</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and let’s implement the methods:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">Response</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">GetName</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span> <span class="k">return</span> <span class="n">r</span><span class="o">.</span><span class="n">Name</span> <span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="o">*</span><span class="n">Response</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">GetSomething</span><span class="p">()</span> <span class="n">SomeThing</span> <span class="p">{</span> <span class="o">..</span><span class="n">logic</span> <span class="n">to</span> <span class="k">return</span> <span class="n">something</span><span class="o">..</span> <span class="p">}</span>

<span class="o">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can then easily reuse this generic struct to instantiate our response types without re-implementing all methods again and again.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">responseOne</span> <span class="o">:=</span> <span class="n">Response</span><span class="p">[</span><span class="n">TypeOneResponse</span><span class="p">]{</span>
    <span class="n">Payload</span><span class="o">:</span> <span class="n">TypeOneResponse</span><span class="p">{</span> <span class="o">...</span> <span class="p">},</span>   
<span class="p">}</span>

<span class="n">responseTwo</span> <span class="o">:=</span> <span class="n">Response</span><span class="p">[</span><span class="n">TypeTwoResponse</span><span class="p">]{</span>
    <span class="n">Payload</span><span class="o">:</span> <span class="n">TypeTwoResponse</span><span class="p">{</span> <span class="o">...</span> <span class="p">},</span>
<span class="p">}</span>

<span class="o">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="real-scenario">Real scenario</h2>

<p>Let’s say we have to use <a href="https://jsonapi.org/">JSON:API</a> format and we want to make sure our custom responses use it.
As I wrote above, it requires our structs to implement the <a href="https://github.com/manyminds/api2go?tab=readme-ov-file#marshalidentifier">dedicated interfaces</a> every time leading to a very messy status.</p>

<p>Let’s say I have a response like this:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">TypeOneResponse</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Field</span><span class="o">:</span> <span class="n">value</span><span class="p">,</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and I want to return it using a JSON:API format, it should result something like this:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
  </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"something"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value"</span><span class="w">
  </span><span class="p">},</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>How to achieve it for all our responses? Implementing implementing implementing. Let’s avoid it using generics.</p>

<p>Let’s create a common Response:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Common</span><span class="p">[</span><span class="n">T</span> <span class="n">any</span><span class="p">]</span> <span class="k">struct</span> <span class="p">{</span>
   <span class="n">ID</span> <span class="kt">string</span> <span class="s">`json:"-"`</span>
   <span class="n">Payload</span> <span class="n">T</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we need to implement all methods as we have seen above:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Common</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">GetID</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span> <span class="k">return</span> <span class="n">c</span><span class="o">.</span><span class="n">ID</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The result will be something like this:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
  </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"something"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"Payload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value"</span><span class="p">,</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>A bit different from what we expected right? We have to get rid of the <code>Payload</code> attribute and have only what it has inside. Let’s fix it implementing our custom <code>MarshalJSON</code> and <code>UnmarshalJSON</code> methods!</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Common</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">MarshalJSON</span><span class="p">()</span> <span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
 <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">Marshal</span><span class="p">(</span><span class="o">&amp;</span><span class="n">c</span><span class="o">.</span><span class="n">Payload</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Common</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">UnmarshalJSON</span><span class="p">(</span><span class="n">v</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
 <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">Unmarshal</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">c</span><span class="o">.</span><span class="n">Payload</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Obtaining as a result:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"something"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value"</span><span class="p">,</span><span class="w">
      </span><span class="p">},</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">  
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Now, every time we want to return our responses, we just need to instantiate our responses in this way:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">resp1</span> <span class="o">:=</span> <span class="n">Common</span><span class="p">[</span><span class="n">TypeOneResponse</span><span class="p">]{</span>
    <span class="n">Payload</span><span class="o">:</span> <span class="n">TypeOneResponse</span><span class="p">{</span>
        <span class="n">Field</span><span class="o">:</span> <span class="n">value</span><span class="p">,</span>
    <span class="p">}}</span>

<span class="n">resp2</span> <span class="o">:=</span> <span class="n">Common</span><span class="p">[</span><span class="n">TypeTwoResponse</span><span class="p">]{</span>
    <span class="n">Payload</span><span class="o">:</span> <span class="n">TypeTwoResponse</span><span class="p">{</span>
        <span class="n">AnotherFieldName</span><span class="o">:</span> <span class="n">value</span><span class="p">,</span>
    <span class="p">}}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Of course, we can further improve readability creating a factory function like:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">NewCommon</span><span class="p">(</span><span class="n">payload</span> <span class="n">T</span><span class="p">,</span> <span class="n">value</span> <span class="n">valueType</span><span class="p">)</span> <span class="n">Common</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and create our custom types:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">CommonOne</span> <span class="n">Common</span><span class="p">[</span><span class="n">TypeOneResponse</span><span class="p">]</span>
<span class="k">type</span> <span class="n">CommonTwo</span> <span class="n">Common</span><span class="p">[</span><span class="n">TypeTwoResponse</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and use them accordingly:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">resp1</span> <span class="o">:=</span> <span class="n">CommonOne</span><span class="p">{</span>
    <span class="n">Payload</span><span class="o">:</span> <span class="n">TypeOneResponse</span><span class="p">{</span>
        <span class="n">Field</span><span class="o">:</span> <span class="n">value</span><span class="p">,</span>
    <span class="p">}}</span>

<span class="n">resp2</span> <span class="o">:=</span> <span class="n">CommonTwo</span><span class="p">{</span>
    <span class="n">Payload</span><span class="o">:</span> <span class="n">TypeTwoResponse</span><span class="p">{</span>
        <span class="n">AnotherFieldName</span><span class="o">:</span> <span class="n">value</span><span class="p">,</span>
    <span class="p">}}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is just a small but very effective example about how to use generics to improve your codebase. Happy coding! :rocket:</p>

      ]]></content:encoded>
    </item><item>
      <title>November 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/11/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/11/01/bookmarks.html</guid>
      <pubDate>Fri, 01 Nov 2024 00:00:00 +0100</pubDate><description>Bookmarks for November 2024: 6 links - What is a Staff Engineer?; Please just stop saying &quot;just&quot;; Breaking Down Tasks - Jacob Kaplan-Moss, and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://nishtahir.com/what-is-a-staff-engineer/">What is a Staff Engineer?</a></li>
  <li><a href="https://sgringwe.com/2019/10/10/Please-just-stop-saying-just.html">Please just stop saying “just”</a></li>
  <li><a href="https://jacobian.org/2024/mar/11/breaking-down-tasks/">Breaking Down Tasks - Jacob Kaplan-Moss</a></li>
  <li><a href="https://archive.is/Bk10R">The Pragmatic Bookshelf - Tell, Don’t Ask</a></li>
  <li><a href="https://news.mit.edu/2024/when-muscles-work-out-they-help-neurons-grow-1112">When muscles work out, they help neurons to grow, a new study shows - MIT News - Massachusetts Institute of Technology</a></li>
  <li><a href="https://flawed.net.nz/2024/11/12/you-are-not-your-job/">flawed.net.nz - Hacking, hardware, software, and general curiosities of computing machinery! Docendo discumus.</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>October 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/10/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/10/01/bookmarks.html</guid>
      <pubDate>Tue, 01 Oct 2024 00:00:00 +0200</pubDate><description>Bookmarks for October 2024: 1 link - Your Brain Changes Based on What You Did Two Weeks Ago -....</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://www.newsweek.com/brain-changes-neuroscience-exercise-sleep-health-two-weeks-1965107">Your Brain Changes Based on What You Did Two Weeks Ago - Newsweek</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>September 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/09/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/09/01/bookmarks.html</guid>
      <pubDate>Sun, 01 Sep 2024 00:00:00 +0200</pubDate><description>Bookmarks for September 2024: 1 link - Go net/http.ServeMux and Trailing Slashes - Xe Iaso.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://xeiaso.net/blog/go-servemux-slash-2021-11-04/">Go net/http.ServeMux and Trailing Slashes - Xe Iaso</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>August 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/08/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/08/01/bookmarks.html</guid>
      <pubDate>Thu, 01 Aug 2024 00:00:00 +0200</pubDate><description>Bookmarks for August 2024: 9 links - Go, a reasonable good language — kokada; The adapter pattern in Go — Bitfield Consu..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://kokada.capivaras.dev/blog/go-a-reasonable-good-language/">Go, a reasonable good language — kokada</a></li>
  <li><a href="https://bitfieldconsulting.com/posts/adapter">The adapter pattern in Go — Bitfield Consulting</a></li>
  <li><a href="https://pkg.go.dev/github.com/data-dog/go-sqlmock">sqlmock package - github.com/data-dog/go-sqlmock - Go Packages</a></li>
  <li><a href="https://bitfieldconsulting.com/posts/api-client">An API client in Go — Bitfield Consulting</a></li>
  <li><a href="https://bitfieldconsulting.com/posts/pointers">Don’t fear the pointer — Bitfield Consulting</a></li>
  <li><a href="https://jvns.ca/blog/2024/08/06/go-structs-copied-on-assignment/">Go structs are copied on assignment (and other things about Go I’d missed)</a></li>
  <li><a href="https://shkspr.mobi/blog/2024/08/psssst-your-date-of-birth-can-be-a-random-number/">Psssst! Your date of birth can be a random number! – Terence Eden’s Blog</a></li>
  <li><a href="https://kerkour.com/programming-vs-software-engineering-rust-vs-go">Programming vs Software Engineering (Rust vs Go)</a></li>
  <li><a href="https://rachel.fast.ai/posts/2024-08-13-crowds-vs-friends/">Rachel Thomas, PhD - Your Immune System is Not a Muscle</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>July 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/07/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/07/01/bookmarks.html</guid>
      <pubDate>Mon, 01 Jul 2024 00:00:00 +0200</pubDate><description>Bookmarks for July 2024: 4 links - Reintroducing engineering thinking in the...; Process doesn’t scale. Knowledge does. - b..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://medium.com/qonto-way/reintroducing-engineering-thinking-in-the-development-world-1541f7cbf1d1">Reintroducing engineering thinking in the development world - by Marc Antoine Lacroix - The Qonto Way - Medium</a></li>
  <li><a href="https://medium.com/qonto-way/process-doesnt-scale-knowledge-does-db0ca2fd6f4b">Process doesn’t scale. Knowledge does. - by Marc Antoine Lacroix - The Qonto Way - Medium</a></li>
  <li><a href="https://medium.com/qonto-way/navigating-complexity-at-scale-qontos-monolithic-domain-driven-design-journey-76a2a08989fa">Navigating Complexity at Scale: Qonto’s Monolithic Domain-Driven Design Journey - by Paweł Rutkowski - The Qonto Way - Medium</a></li>
  <li><a href="https://medium.com/qonto-way/how-value-engineering-helps-us-ship-predictably-40d5d0193426">How Value Engineering helps us ship predictably - by Claire Krucker - The Qonto Way - Medium</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>Create a DNS Resolver with Golang</title>
      <link>https://domenicoluciani.com/2024/05/07/create-dns-resolver.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/05/07/create-dns-resolver.html</guid>
      <pubDate>Tue, 07 May 2024 00:00:00 +0200</pubDate><description>Following the previous post about creating an Application Layer Load Balancer, today I&apos;m going to share my journey about another challenge I took and completed: Create a simple…</description>
      <content:encoded><![CDATA[
<p>Following the previous post about <a href="https://domenicoluciani.com/2024/02/12/creating-an-application-layer-load-balancer.html">creating an Application Layer Load Balancer</a>, today I’m going to share my journey about another challenge I took and completed:
<strong>Create a simple DNS Resolver with Go</strong>, let’s go! 🚀</p>

<h2 id="dns-resolver-what">DNS Resolver what?</h2>

<p>A DNS Resolver is a crucial component that allows you to resolve an IP address from a certain domain. <br />
For instance, it allows your browser to know where to find the server associated with a specific domain. <br />
(i.e. domenicoluciani.com → 172.67.144.42)</p>

<h2 id="the-coding-challenge">The Coding Challenge</h2>

<p>The coding challenge consists of building a simple DNS Resolver that is capable of resolving an IP address from a certain domain. I’d like to highlight about the <em>simple</em> part. <br />
You can find the challenge here: <a href="https://codingchallenges.fyi/challenges/challenge-dns-resolver/">https://codingchallenges.fyi/challenges/challenge-dns-resolver/</a></p>

<h2 id="preface">Preface</h2>
<p>As I did in the previous posts, I took this challenge just for fun and dive deeper into how a DNS resolver works. It’s a weekend project that obviously can contain errors, so if you find one -or more-, please let me know, never stop learning, right? 📚</p>

<h2 id="things-i-learned-with-this-challenge">Things I learned with this challenge</h2>

<ul>
  <li>Obviously, I learned <strong>A LOT</strong> about how a DNS Resolver works.</li>
  <li>How the name resolution works</li>
  <li>What encoding is used</li>
  <li>Went deeper into binary protocols and how they work
    <ul>
      <li>And how to fill a structure with binary data in Go.</li>
    </ul>
  </li>
  <li>The <a href="https://datatracker.ietf.org/doc/html/rfc1035">DNS RFC</a> is super clear (well done authors!)</li>
  <li>Testing and ChatGPT saved me from a lot of debugging time</li>
</ul>

<p>Are you interested in one of these things? Then keep reading! 🕵🏻‍♂️</p>

<h2 id="step-0">Step 0</h2>

<p>For this challenge, I decided to use Go and I tried to use a Test Driven Development approach as usual, even tho not completely since my goal wasn’t to apply it perfectly but to have a good simple design. 🙏🏻</p>

<h2 id="step-1">Step 1</h2>
<p>This step is about creating a query message that we have to send to the name server, composed of these fields:</p>

<ol>
  <li>A header.</li>
  <li>A question section.</li>
  <li>An answer section.</li>
  <li>An authority section.</li>
  <li>An additional section.</li>
</ol>

<h2 id="header">Header</h2>
<p>The header is always present, and it is composed in this way</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre>                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Query ID</li>
  <li>Some flags (at the beginning for the challenge we set this flags to 1 and then to 0 because at the beginning we contact a dns resolver to then switch to an authoritative nameserver)</li>
  <li>QDCOUNT = Number of questions</li>
  <li>ANCOUNT = Number of answers</li>
  <li>NSCOUNT =  Number of authorities</li>
  <li>ARCOUNT = Number of additional</li>
</ul>

<p>You can see the detail in the RFC, <a href="https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1">section 4.1.1</a>.</p>

<h2 id="question">Question</h2>

<p>The question section is composed in this way:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre>                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                     QNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QTYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QCLASS                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

</pre></td></tr></tbody></table></code></pre></div></div>
<ul>
  <li>QNAME = encoded name of the domain (i.e. <code>3dns6google3com</code>)</li>
  <li>QTYPE = the type of the query (i.e. <code>A</code>, <code>MX</code>, etc.)</li>
  <li>QCLASS = class type (i.e. <code>internet</code>)</li>
</ul>

<p>The details are defined in these sections of the RFC:</p>
<ul>
  <li>Question: <a href="https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.2">https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.2</a></li>
  <li>Type: <a href="https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.2">https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.2</a></li>
  <li>Class: <a href="https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.2">https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.4</a></li>
</ul>

<h2 id="query">Query</h2>
<p>Both sections need to be encoded in bytes and put together in order to form the final query.</p>

<p>When we send the request we don’t don’t need to compose authorities and additionals, they are going to be filled out in the response.</p>

<h2 id="lets-see-the-code-">Let’s see the code 👀</h2>

<p>Let’s take a look at how I created and converted these two structures into bytes.</p>

<p>The test is quite minimal and simple:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should encode an header into bytes"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">header</span> <span class="o">:=</span> <span class="n">NewHeader</span><span class="p">(</span><span class="m">22</span><span class="p">,</span> <span class="n">RECURSION_FLAG</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>

        <span class="n">encodedHeader</span> <span class="o">:=</span> <span class="n">header</span><span class="o">.</span><span class="n">ToBytes</span><span class="p">()</span>

        <span class="n">expected</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"0016010000010000000000000"</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">NotNil</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">encodedHeader</span><span class="p">)</span>
    <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">const</span> <span class="n">RECURSION_FLAG</span> <span class="kt">uint16</span> <span class="o">=</span> <span class="m">1</span> <span class="o">&lt;&lt;</span> <span class="m">8</span>

<span class="k">type</span> <span class="n">Header</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Id</span>      <span class="kt">uint16</span>
    <span class="n">Flags</span>   <span class="kt">uint16</span>
    <span class="n">QdCount</span> <span class="kt">uint16</span>
    <span class="n">AnCount</span> <span class="kt">uint16</span>
    <span class="n">NsCount</span> <span class="kt">uint16</span>
    <span class="n">ArCount</span> <span class="kt">uint16</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>and then I implemented the function for the conversion:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">h</span> <span class="o">*</span><span class="n">Header</span><span class="p">)</span> <span class="n">ToBytes</span><span class="p">()</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
    <span class="n">encodedHeader</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="n">bytes</span><span class="o">.</span><span class="n">Buffer</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedHeader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">Id</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedHeader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">Flags</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedHeader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">QdCount</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedHeader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">AnCount</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedHeader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">NsCount</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedHeader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">ArCount</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">encodedHeader</span><span class="o">.</span><span class="n">Bytes</span><span class="p">()</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The go <a href="https://pkg.go.dev/encoding/binary">encoding/binary</a> package was crucial to working with anything related to the binary encoding. <br />
Basically, I just append into <code>encodedHeader</code> <code>bytes.Buffer</code> whatever I have on each field of the struct using a Big-endian order.</p>

<p>I have done the same thing for the question part:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should encode a question into bytes"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">question</span> <span class="o">:=</span> <span class="n">NewQuestion</span><span class="p">(</span><span class="s">"dns.google.com"</span><span class="p">,</span> <span class="n">TYPE_A</span><span class="p">,</span> <span class="n">CLASS_IN</span><span class="p">)</span>

        <span class="n">encodedQuestion</span> <span class="o">:=</span> <span class="n">question</span><span class="o">.</span><span class="n">ToBytes</span><span class="p">()</span>

        <span class="n">expected</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"03646e7306676f6f676c6503636f6d0000010001"</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">NotNil</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">encodedQuestion</span><span class="p">)</span>
    <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>and the implementation</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">q</span> <span class="o">*</span><span class="n">Question</span><span class="p">)</span> <span class="n">ToBytes</span><span class="p">()</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
    <span class="n">encodedQuestion</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="n">bytes</span><span class="o">.</span><span class="n">Buffer</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedQuestion</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">q</span><span class="o">.</span><span class="n">QName</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedQuestion</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">q</span><span class="o">.</span><span class="n">QType</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">encodedQuestion</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="n">q</span><span class="o">.</span><span class="n">QClass</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">encodedQuestion</span><span class="o">.</span><span class="n">Bytes</span><span class="p">()</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>One thing here is that we have to encode the domain name using a simple encoding algorithm, here the test:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should encode the dns name"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">encodedDnsName</span> <span class="o">:=</span> <span class="n">encodeDnsName</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"dns.google.com"</span><span class="p">))</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"</span><span class="se">\x03</span><span class="s">dns</span><span class="se">\x06</span><span class="s">google</span><span class="se">\x03</span><span class="s">com</span><span class="se">\x00</span><span class="s">"</span><span class="p">),</span> <span class="n">encodedDnsName</span><span class="p">)</span>
    <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Basically we replace each dot with a number of characters we have right after it, so <code>dns.google.com</code> becomes <code>3dns6google3com</code>.</p>

<p>The implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">encodeDnsName</span><span class="p">(</span><span class="n">qname</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">encoded</span> <span class="p">[]</span><span class="kt">byte</span>
    <span class="n">parts</span> <span class="o">:=</span> <span class="n">bytes</span><span class="o">.</span><span class="n">Split</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="n">qname</span><span class="p">),</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">{</span><span class="sc">'.'</span><span class="p">})</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">part</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">parts</span> <span class="p">{</span>
        <span class="n">encoded</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">encoded</span><span class="p">,</span> <span class="kt">byte</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">part</span><span class="p">)))</span>
        <span class="n">encoded</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">encoded</span><span class="p">,</span> <span class="n">part</span><span class="o">...</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">append</span><span class="p">(</span><span class="n">encoded</span><span class="p">,</span> <span class="m">0x00</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and now let’s join both header and question together, the test:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should create a query"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">header</span> <span class="o">:=</span> <span class="n">NewHeader</span><span class="p">(</span><span class="m">22</span><span class="p">,</span> <span class="n">RECURSION_FLAG</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>
        <span class="n">question</span> <span class="o">:=</span> <span class="n">NewQuestion</span><span class="p">(</span><span class="s">"dns.google.com"</span><span class="p">,</span> <span class="n">TYPE_A</span><span class="p">,</span> <span class="n">CLASS_IN</span><span class="p">)</span>

        <span class="n">query</span> <span class="o">:=</span> <span class="n">NewQuery</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">question</span><span class="p">)</span>

        <span class="n">expected</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"00160100000100000000000003646e7306676f6f676c6503636f6d0000010001"</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Nil</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
    <span class="p">})</span>

</pre></td></tr></tbody></table></code></pre></div></div>

<p>and the resulting code:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">NewQuery</span><span class="p">(</span><span class="n">header</span> <span class="o">*</span><span class="n">Header</span><span class="p">,</span> <span class="n">question</span> <span class="o">*</span><span class="n">Question</span><span class="p">)</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">query</span> <span class="p">[]</span><span class="kt">byte</span>

    <span class="n">query</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">header</span><span class="o">.</span><span class="n">ToBytes</span><span class="p">()</span><span class="o">...</span><span class="p">)</span>
    <span class="n">query</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">question</span><span class="o">.</span><span class="n">ToBytes</span><span class="p">()</span><span class="o">...</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">query</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="step-2">Step 2</h2>

<p>Now we need to send our query over the network using the <em>UDP</em> protocol and get back the response from the name server. <br />
The code is quite simple, I didn’t want to spend much time on error checking tho, here is the implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Client</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">serverAddress</span> <span class="kt">string</span>
    <span class="n">port</span>          <span class="kt">int</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">NewClient</span><span class="p">(</span><span class="n">address</span> <span class="kt">string</span><span class="p">,</span> <span class="n">port</span> <span class="kt">int</span><span class="p">)</span> <span class="o">*</span><span class="n">Client</span> <span class="p">{</span>
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">Client</span><span class="p">{</span><span class="n">serverAddress</span><span class="o">:</span> <span class="n">address</span><span class="p">,</span> <span class="n">port</span><span class="o">:</span> <span class="n">port</span><span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Client</span><span class="p">)</span> <span class="n">SendQuery</span><span class="p">(</span><span class="n">query</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
    <span class="n">conn</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">net</span><span class="o">.</span><span class="n">Dial</span><span class="p">(</span><span class="s">"udp"</span><span class="p">,</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%s:%d"</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">serverAddress</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">port</span><span class="p">))</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Dial err %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="n">os</span><span class="o">.</span><span class="n">Exit</span><span class="p">(</span><span class="o">-</span><span class="m">1</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="k">defer</span> <span class="n">conn</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

    <span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">query</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Write err %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="n">os</span><span class="o">.</span><span class="n">Exit</span><span class="p">(</span><span class="o">-</span><span class="m">1</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="n">response</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">1024</span><span class="p">)</span>
    <span class="n">lengthOfTheResponse</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">conn</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Read err %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="n">os</span><span class="o">.</span><span class="n">Exit</span><span class="p">(</span><span class="o">-</span><span class="m">1</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="o">!</span><span class="n">hasTheSameID</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Response doesn't have the same ID of the query q:%v, r:%v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">query</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span>
        <span class="n">os</span><span class="o">.</span><span class="n">Exit</span><span class="p">(</span><span class="o">-</span><span class="m">1</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">response</span><span class="p">[</span><span class="o">:</span><span class="n">lengthOfTheResponse</span><span class="p">]</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>One check I had to implement due of requirements is about the query ID (it can be whatever), the one we send should be the same as the one that we receive from the server, here the test:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should check if the response starts with the same ID as the query"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">query</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"00160100000100000000000003646e7306676f6f676c6503636f6d0000010001"</span><span class="p">)</span>
        <span class="n">response</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"00168080000100020000000003646e7306676f6f676c6503636f6d0000010001c00c0001000100000214000408080808c00c0001000100000214000408080404"</span><span class="p">)</span>

        <span class="n">assert</span><span class="o">.</span><span class="n">True</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">hasTheSameID</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">response</span><span class="p">))</span>
    <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and the implementation:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">hasTheSameID</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">response</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">slices</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">query</span><span class="p">[</span><span class="o">:</span><span class="m">2</span><span class="p">],</span> <span class="n">response</span><span class="p">[</span><span class="o">:</span><span class="m">2</span><span class="p">])</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="step-3">Step 3</h2>

<p>Now our goal is to parse the response, the message luckily has the same structure as the one we sent, let’s see how to parse the header:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should create an header from a response"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">response</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"001680800001000200000000"</span><span class="p">)</span>
        <span class="n">header</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">ParseHeader</span><span class="p">(</span><span class="n">bytes</span><span class="o">.</span><span class="n">NewReader</span><span class="p">(</span><span class="n">response</span><span class="p">))</span>

        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Header</span><span class="p">{</span>
            <span class="n">Id</span><span class="o">:</span>      <span class="m">0x16</span><span class="p">,</span>
            <span class="n">Flags</span><span class="o">:</span>   <span class="m">1</span><span class="o">&lt;&lt;</span><span class="m">15</span> <span class="o">|</span> <span class="m">1</span><span class="o">&lt;&lt;</span><span class="m">7</span><span class="p">,</span> <span class="c">// QR (Response) bit = 1, OPCODE = 0 (standard query), AA = 1, TC = 0, RD (Recursion Desired) bit = 1, RA = 1, Z = 0, RCODE = 0</span>
            <span class="n">QdCount</span><span class="o">:</span> <span class="m">0x1</span><span class="p">,</span>
            <span class="n">AnCount</span><span class="o">:</span> <span class="m">0x2</span><span class="p">,</span>
            <span class="n">NsCount</span><span class="o">:</span> <span class="m">0x0</span><span class="p">,</span>
            <span class="n">ArCount</span><span class="o">:</span> <span class="m">0x0</span><span class="p">,</span>
        <span class="p">},</span> <span class="n">header</span><span class="p">)</span>
    <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>and the implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">ParseHeader</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="n">Header</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">header</span> <span class="n">Header</span>

    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">header</span><span class="o">.</span><span class="n">Id</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">header</span><span class="o">.</span><span class="n">Flags</span><span class="p">)</span>
    <span class="k">switch</span> <span class="n">header</span><span class="o">.</span><span class="n">Flags</span> <span class="o">&amp;</span> <span class="m">0</span><span class="n">b1111</span> <span class="p">{</span>
    <span class="k">case</span> <span class="m">1</span><span class="o">:</span>
        <span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"error with the query"</span><span class="p">)</span>
    <span class="k">case</span> <span class="m">2</span><span class="o">:</span>
        <span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"error with the server"</span><span class="p">)</span>
    <span class="k">case</span> <span class="m">3</span><span class="o">:</span>
        <span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"the domain doesn't exist"</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">header</span><span class="o">.</span><span class="n">QdCount</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">header</span><span class="o">.</span><span class="n">AnCount</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">header</span><span class="o">.</span><span class="n">NsCount</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">header</span><span class="o">.</span><span class="n">ArCount</span><span class="p">)</span>

    <span class="k">return</span> <span class="o">&amp;</span><span class="n">header</span><span class="p">,</span> <span class="no">nil</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Thanks to the <code>encoding/binary</code> package we can easily get the information we need and store it into our structure. <br />
Here I also implemented a check to verify that the response didn’t have  errors.
Thanks to ChatGPT I could easily generate the binary response for each use-case otherwise I would have had to do it by myself 😫</p>

<p>The tests are more or less like this:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should return an error if the header flags contains a query error"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">response</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"001680810001000200000000"</span><span class="p">)</span>

        <span class="n">header</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">ParseHeader</span><span class="p">(</span><span class="n">bytes</span><span class="o">.</span><span class="n">NewReader</span><span class="p">(</span><span class="n">response</span><span class="p">))</span>

        <span class="n">assert</span><span class="o">.</span><span class="n">Nil</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">header</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">NotNil</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">EqualError</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">err</span><span class="p">,</span> <span class="s">"error with the query"</span><span class="p">)</span>
    <span class="p">})</span>

</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now let’s parse the rest of the message:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">ParseQuestion</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">)</span> <span class="o">*</span><span class="n">Question</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">question</span> <span class="n">Question</span>

    <span class="n">question</span><span class="o">.</span><span class="n">QName</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="n">DecodeName</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">question</span><span class="o">.</span><span class="n">QType</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">question</span><span class="o">.</span><span class="n">QClass</span><span class="p">)</span>

    <span class="k">return</span> <span class="o">&amp;</span><span class="n">question</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we see a <code>DecodeName</code> function, which is the most difficult part in terms of implementation for the DNS Resolver:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">DecodeName</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">name</span> <span class="n">bytes</span><span class="o">.</span><span class="n">Buffer</span>

    <span class="k">for</span> <span class="p">{</span>
        <span class="n">lengthByte</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">reader</span><span class="o">.</span><span class="n">ReadByte</span><span class="p">()</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">lengthByte</span> <span class="o">&amp;</span> <span class="m">0xC0</span><span class="p">)</span> <span class="o">==</span> <span class="m">0xC0</span> <span class="p">{</span>
            <span class="n">name</span><span class="o">.</span><span class="n">WriteString</span><span class="p">(</span><span class="n">getBackTheDomainFromTheHeader</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">lengthByte</span><span class="p">))</span>
            <span class="k">break</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="n">lengthByte</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>
            <span class="k">break</span>
        <span class="p">}</span>

        <span class="n">label</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="n">lengthByte</span><span class="p">)</span>
        <span class="n">io</span><span class="o">.</span><span class="n">ReadFull</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span>
        <span class="n">name</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">label</span><span class="p">)</span>
        <span class="n">name</span><span class="o">.</span><span class="n">WriteByte</span><span class="p">(</span><span class="sc">'.'</span><span class="p">)</span>

    <span class="p">}</span>

    <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">CutSuffix</span><span class="p">(</span><span class="n">name</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span> <span class="s">"."</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">getBackTheDomainFromTheHeader</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">,</span> <span class="n">lengthByte</span> <span class="kt">byte</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
    <span class="n">nextByte</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">reader</span><span class="o">.</span><span class="n">ReadByte</span><span class="p">()</span>
    <span class="n">pointer</span> <span class="o">:=</span> <span class="kt">uint16</span><span class="p">((</span><span class="kt">uint16</span><span class="p">(</span><span class="n">lengthByte</span><span class="p">)</span> <span class="o">&amp;</span> <span class="m">0x3F</span><span class="p">)</span> <span class="o">|</span> <span class="kt">uint16</span><span class="p">(</span><span class="n">nextByte</span><span class="p">))</span>

    <span class="n">currentPos</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">reader</span><span class="o">.</span><span class="n">Seek</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">io</span><span class="o">.</span><span class="n">SeekCurrent</span><span class="p">)</span>

    <span class="n">reader</span><span class="o">.</span><span class="n">Seek</span><span class="p">(</span><span class="kt">int64</span><span class="p">(</span><span class="n">pointer</span><span class="p">),</span> <span class="n">io</span><span class="o">.</span><span class="n">SeekStart</span><span class="p">)</span>

    <span class="n">decodedName</span> <span class="o">:=</span> <span class="n">DecodeName</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>

    <span class="n">reader</span><span class="o">.</span><span class="n">Seek</span><span class="p">(</span><span class="n">currentPos</span><span class="p">,</span> <span class="n">io</span><span class="o">.</span><span class="n">SeekStart</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">decodedName</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I created a recursive function for simplicity; basically if the buffer starts with <code>0xC0</code> it means we are in front of a “DNS compression algorithm”.</p>

<p>The algorithm consists of a pointer towards the domain name we previously got in the buffer in order to not being repeated and save space. So, we calculate the offset, move there, read the domain name, and then get back to the original position, continuing with the parsing.</p>

<p>Of course this is a very basic algorithm and it can lead to <a href="https://jvns.ca/blog/2022/01/15/some-ways-dns-can-break/">multiple problems</a> (like for example a malicious server can create a pointer to itself creating an infinite loop but you know, it was out of the scope of this challenge 😇)</p>

<p>And last but not the least, let’s parse the records we got:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre>
<span class="k">func</span> <span class="n">TestResponse</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Should create a record from a response"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">response</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">DecodeString</span><span class="p">(</span><span class="s">"00168080000100020000000003646e7306676f6f676c6503636f6d0000010001c00c0001000100000214000408080808c00c0001000100000214000408080404"</span><span class="p">)</span>
        <span class="n">reader</span> <span class="o">:=</span> <span class="n">bytes</span><span class="o">.</span><span class="n">NewReader</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
        <span class="k">const</span> <span class="n">RECORD_STARTING_POINT</span> <span class="o">=</span> <span class="m">32</span>
        <span class="n">skipResponseTill</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">reader</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="n">RECORD_STARTING_POINT</span><span class="p">)</span>

        <span class="n">record</span> <span class="o">:=</span> <span class="n">ParseRecord</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>

        <span class="n">assert</span><span class="o">.</span><span class="n">NotEmpty</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">record</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">TYPE_A</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">Type</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">CLASS_IN</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">Class</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Greater</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">TTL</span><span class="p">,</span> <span class="kt">uint32</span><span class="p">(</span><span class="m">0</span><span class="p">))</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Greater</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">RdLength</span><span class="p">,</span> <span class="kt">uint16</span><span class="p">(</span><span class="m">0</span><span class="p">))</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"8.8.8.8"</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">Rdata</span><span class="p">)</span>

        <span class="n">record</span> <span class="o">=</span> <span class="n">ParseRecord</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>

        <span class="n">assert</span><span class="o">.</span><span class="n">NotEmpty</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">record</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">TYPE_A</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">Type</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">CLASS_IN</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">Class</span><span class="p">)</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Greater</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">TTL</span><span class="p">,</span> <span class="kt">uint32</span><span class="p">(</span><span class="m">0</span><span class="p">))</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Greater</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">RdLength</span><span class="p">,</span> <span class="kt">uint16</span><span class="p">(</span><span class="m">0</span><span class="p">))</span>
        <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"8.8.4.4"</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">Rdata</span><span class="p">)</span>
    <span class="p">})</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">skipResponseTill</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">,</span> <span class="n">response</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">,</span> <span class="n">startingPoint</span> <span class="kt">int64</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">t</span><span class="o">.</span><span class="n">Helper</span><span class="p">()</span>
    <span class="n">reader</span><span class="o">.</span><span class="n">ReadAt</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">startingPoint</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>Here I could have added more tests and use-cases I know, I’ll leave it to you as a homework. 😎</p>

<p>The implementation:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Record</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Name</span>     <span class="p">[]</span><span class="kt">byte</span>
    <span class="n">Type</span>     <span class="kt">uint16</span>
    <span class="n">Class</span>    <span class="kt">uint16</span>
    <span class="n">TTL</span>      <span class="kt">uint32</span>
    <span class="n">RdLength</span> <span class="kt">uint16</span>
    <span class="n">Rdata</span>    <span class="kt">string</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">ParseRecord</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">)</span> <span class="o">*</span><span class="n">Record</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">record</span> <span class="n">Record</span>
    <span class="n">record</span><span class="o">.</span><span class="n">Name</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="n">DecodeName</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">record</span><span class="o">.</span><span class="n">Type</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">record</span><span class="o">.</span><span class="n">Class</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">record</span><span class="o">.</span><span class="n">TTL</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">record</span><span class="o">.</span><span class="n">RdLength</span><span class="p">)</span>
    <span class="k">switch</span> <span class="n">record</span><span class="o">.</span><span class="n">Type</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">TYPE_A</span><span class="o">:</span>
        <span class="n">record</span><span class="o">.</span><span class="n">Rdata</span> <span class="o">=</span> <span class="n">readIP</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">RdLength</span><span class="p">)</span>
    <span class="k">case</span> <span class="n">TYPE_NS</span><span class="o">:</span>
        <span class="n">record</span><span class="o">.</span><span class="n">Rdata</span> <span class="o">=</span> <span class="n">DecodeName</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
    <span class="k">default</span><span class="o">:</span>
        <span class="n">record</span><span class="o">.</span><span class="n">Rdata</span> <span class="o">=</span> <span class="kt">string</span><span class="p">(</span><span class="n">readData</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">RdLength</span><span class="p">))</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">record</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">readIP</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">,</span> <span class="n">length</span> <span class="kt">uint16</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
    <span class="n">dataBytes</span> <span class="o">:=</span> <span class="n">readData</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%d.%d.%d.%d"</span><span class="p">,</span> <span class="n">dataBytes</span><span class="p">[</span><span class="m">0</span><span class="p">],</span> <span class="n">dataBytes</span><span class="p">[</span><span class="m">1</span><span class="p">],</span> <span class="n">dataBytes</span><span class="p">[</span><span class="m">2</span><span class="p">],</span> <span class="n">dataBytes</span><span class="p">[</span><span class="m">3</span><span class="p">])</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">readData</span><span class="p">(</span><span class="n">reader</span> <span class="o">*</span><span class="n">bytes</span><span class="o">.</span><span class="n">Reader</span><span class="p">,</span> <span class="n">length</span> <span class="kt">uint16</span><span class="p">)</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
    <span class="n">dataBytes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
    <span class="n">binary</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">binary</span><span class="o">.</span><span class="n">BigEndian</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">dataBytes</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">dataBytes</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we can see how we differentiate between <code>TYPE_A</code> and <code>TYPE_NS</code> in order to be able to decode the domain correctly. This is important because with the first type we get an IP, with the second a domain name.</p>

<p>The record part is the most important one because it might be:</p>
<ul>
  <li><code>ANSWER</code>: A list of IP addresses, basically what we are looking for</li>
  <li><code>AUTHORITIES</code>: A list of NS servers that potentially can have what we are looking for</li>
  <li><code>ADDITIONALS</code>: A list of IP addresses of the NS servers we got from the <code>AUTHORITITES</code> section.</li>
</ul>

<h2 id="lets-put-everything-together">Let’s put everything together</h2>
<p>Now it’s time to use all these function together:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">resolve</span><span class="p">(</span><span class="n">domainName</span> <span class="kt">string</span><span class="p">,</span> <span class="n">questionType</span> <span class="kt">uint16</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="n">nameServer</span> <span class="o">:=</span> <span class="s">"198.41.0.4"</span>
	<span class="k">for</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Querying %s for %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">nameServer</span><span class="p">,</span> <span class="n">domainName</span><span class="p">)</span>
		<span class="n">dnsResponse</span> <span class="o">:=</span> <span class="n">sendQuery</span><span class="p">(</span><span class="n">nameServer</span><span class="p">,</span> <span class="n">domainName</span><span class="p">,</span> <span class="n">questionType</span><span class="p">)</span>
		<span class="n">dnsPacket</span> <span class="o">:=</span> <span class="n">getDnsPacketFromResponse</span><span class="p">(</span><span class="n">dnsResponse</span><span class="p">)</span>

		<span class="k">if</span> <span class="n">ip</span> <span class="o">:=</span> <span class="n">getAnswer</span><span class="p">(</span><span class="n">dnsPacket</span><span class="o">.</span><span class="n">answers</span><span class="p">);</span> <span class="n">ip</span> <span class="o">!=</span> <span class="s">""</span> <span class="p">{</span>
			<span class="k">return</span> <span class="n">ip</span>
		<span class="p">}</span>

		<span class="k">if</span> <span class="n">nsIp</span> <span class="o">:=</span> <span class="n">getNameServerIp</span><span class="p">(</span><span class="n">dnsPacket</span><span class="o">.</span><span class="n">additionals</span><span class="p">);</span> <span class="n">nsIp</span> <span class="o">!=</span> <span class="s">""</span> <span class="p">{</span>
			<span class="n">nameServer</span> <span class="o">=</span> <span class="n">nsIp</span>
			<span class="k">continue</span>
		<span class="p">}</span>

		<span class="k">if</span> <span class="n">nsDomain</span> <span class="o">:=</span> <span class="n">getNameServer</span><span class="p">(</span><span class="n">dnsPacket</span><span class="o">.</span><span class="n">authorities</span><span class="p">);</span> <span class="n">nsDomain</span> <span class="o">!=</span> <span class="s">""</span> <span class="p">{</span>
			<span class="n">nameServer</span> <span class="o">=</span> <span class="n">resolve</span><span class="p">(</span><span class="n">nsDomain</span><span class="p">,</span> <span class="n">packet</span><span class="o">.</span><span class="n">TYPE_A</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Where <code>SendQuery</code>:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">sendQuery</span><span class="p">(</span><span class="n">nameServer</span><span class="p">,</span> <span class="n">domainName</span> <span class="kt">string</span><span class="p">,</span> <span class="n">questionType</span> <span class="kt">uint16</span><span class="p">)</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>
	<span class="n">query</span> <span class="o">:=</span> <span class="n">packet</span><span class="o">.</span><span class="n">NewQuery</span><span class="p">(</span>
		<span class="n">packet</span><span class="o">.</span><span class="n">NewHeader</span><span class="p">(</span><span class="m">22</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span>
		<span class="n">packet</span><span class="o">.</span><span class="n">NewQuestion</span><span class="p">(</span><span class="n">domainName</span><span class="p">,</span> <span class="n">questionType</span><span class="p">,</span> <span class="n">packet</span><span class="o">.</span><span class="n">CLASS_IN</span><span class="p">),</span>
	<span class="p">)</span>

	<span class="n">client</span> <span class="o">:=</span> <span class="n">network</span><span class="o">.</span><span class="n">NewClient</span><span class="p">(</span><span class="n">nameServer</span><span class="p">,</span> <span class="m">53</span><span class="p">)</span>
	<span class="k">return</span> <span class="n">client</span><span class="o">.</span><span class="n">SendQuery</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Creates the query from the header and the question and then send the query to the nameserver.</p>

<p>Then we get the <code>DNSPacket</code> from the response parsing it:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">getDnsPacketFromResponse</span><span class="p">(</span><span class="n">dnsResponse</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="o">*</span><span class="n">DNSPacket</span> <span class="p">{</span>
	<span class="k">var</span> <span class="p">(</span>
		<span class="n">header</span>      <span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Header</span>
		<span class="n">questions</span>   <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Question</span>
		<span class="n">answers</span>     <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span>
		<span class="n">authorities</span> <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span>
		<span class="n">additionals</span> <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span>
	<span class="p">)</span>

	<span class="n">reader</span> <span class="o">:=</span> <span class="n">bytes</span><span class="o">.</span><span class="n">NewReader</span><span class="p">(</span><span class="n">dnsResponse</span><span class="p">)</span>
	<span class="n">header</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">packet</span><span class="o">.</span><span class="n">ParseHeader</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Can't parse the response header: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
		<span class="n">os</span><span class="o">.</span><span class="n">Exit</span><span class="p">(</span><span class="o">-</span><span class="m">1</span><span class="p">)</span>
	<span class="p">}</span>
	<span class="k">for</span> <span class="k">range</span> <span class="n">header</span><span class="o">.</span><span class="n">QdCount</span> <span class="p">{</span>
		<span class="n">questions</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">questions</span><span class="p">,</span> <span class="n">packet</span><span class="o">.</span><span class="n">ParseQuestion</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
	<span class="p">}</span>

	<span class="k">for</span> <span class="k">range</span> <span class="n">header</span><span class="o">.</span><span class="n">AnCount</span> <span class="p">{</span>
		<span class="n">answers</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">answers</span><span class="p">,</span> <span class="n">packet</span><span class="o">.</span><span class="n">ParseRecord</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
	<span class="p">}</span>

	<span class="k">for</span> <span class="k">range</span> <span class="n">header</span><span class="o">.</span><span class="n">NsCount</span> <span class="p">{</span>
		<span class="n">authorities</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">authorities</span><span class="p">,</span> <span class="n">packet</span><span class="o">.</span><span class="n">ParseRecord</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
	<span class="p">}</span>

	<span class="k">for</span> <span class="k">range</span> <span class="n">header</span><span class="o">.</span><span class="n">ArCount</span> <span class="p">{</span>
		<span class="n">additionals</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">additionals</span><span class="p">,</span> <span class="n">packet</span><span class="o">.</span><span class="n">ParseRecord</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="o">&amp;</span><span class="n">DNSPacket</span><span class="p">{</span>
		<span class="n">header</span><span class="o">:</span>      <span class="n">header</span><span class="p">,</span>
		<span class="n">questions</span><span class="o">:</span>   <span class="n">questions</span><span class="p">,</span>
		<span class="n">answers</span><span class="o">:</span>     <span class="n">answers</span><span class="p">,</span>
		<span class="n">authorities</span><span class="o">:</span> <span class="n">authorities</span><span class="p">,</span>
		<span class="n">additionals</span><span class="o">:</span> <span class="n">additionals</span><span class="p">,</span>
	<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and at the end we check what results we get from the other sections:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">getAnswer</span><span class="p">(</span><span class="n">answers</span> <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">getRecord</span><span class="p">(</span><span class="n">answers</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">getNameServerIp</span><span class="p">(</span><span class="n">additionals</span> <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">getRecord</span><span class="p">(</span><span class="n">additionals</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">getNameServer</span><span class="p">(</span><span class="n">authorities</span> <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">getRecord</span><span class="p">(</span><span class="n">authorities</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">getRecord</span><span class="p">(</span><span class="n">records</span> <span class="p">[]</span><span class="o">*</span><span class="n">packet</span><span class="o">.</span><span class="n">Record</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">record</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">records</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">record</span><span class="o">.</span><span class="n">Type</span> <span class="o">==</span> <span class="n">packet</span><span class="o">.</span><span class="n">TYPE_A</span> <span class="o">||</span> <span class="n">record</span><span class="o">.</span><span class="n">Type</span> <span class="o">==</span> <span class="n">packet</span><span class="o">.</span><span class="n">TYPE_NS</span> <span class="p">{</span>
			<span class="k">return</span> <span class="n">record</span><span class="o">.</span><span class="n">Rdata</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="s">""</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="the-code-and-the-output">The code and the output?</h2>

<p>As always you can find the code on my Github, at this url: <a href="https://github.com/dlion/unnije">https://github.com/dlion/unnije</a>.</p>

<p>And the output looks like this:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>dlion@darkness&gt; unnije % ./unnije domenicoluciani.com
Querying 198.41.0.4 <span class="k">for </span>domenicoluciani.com
Querying 192.41.162.30 <span class="k">for </span>domenicoluciani.com
Querying 108.162.192.65 <span class="k">for </span>domenicoluciani.com
104.21.47.30
</pre></td></tr></tbody></table></code></pre></div></div>
<p>or</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre>dlion@darkness unnije % ./unnije domenicoluciani.com twitter.com
Querying 198.41.0.4 <span class="k">for </span>domenicoluciani.com
Querying 192.41.162.30 <span class="k">for </span>domenicoluciani.com
Querying 108.162.192.65 <span class="k">for </span>domenicoluciani.com
172.67.144.42
Querying 198.41.0.4 <span class="k">for </span>twitter.com
Querying 192.41.162.30 <span class="k">for </span>twitter.com
Querying 198.41.0.4 <span class="k">for </span>a.r06.twtrdns.net
Querying 192.55.83.30 <span class="k">for </span>a.r06.twtrdns.net
Querying 205.251.195.207 <span class="k">for </span>a.r06.twtrdns.net
Querying 205.251.192.179 <span class="k">for </span>twitter.com
104.244.42.129
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If we want to try providing more than one domain.</p>

<h2 id="final-thoughts-and-thank-yous">Final thoughts and thank yous</h2>

<p>I had lot of fun doing this challenge, I studied how the DNS works in the past but I’ve been so close to the actual implementation and I will never stop saying that theory is nothing without a good practice.</p>

<p>Some articles I found helpful to understand better how to overcome this challenge:</p>
<ul>
  <li><a href="https://datatracker.ietf.org/doc/html/rfc1035">DNS RFC</a></li>
  <li>Julia Evans blog:
    <ul>
      <li><a href="https://jvns.ca/blog/2023/07/28/why-is-dns-still-hard-to-learn/">https://jvns.ca/blog/2023/07/28/why-is-dns-still-hard-to-learn/</a></li>
      <li><a href="https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/">https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/</a></li>
      <li><a href="https://jvns.ca/blog/2022/02/14/some-dns-terminology/">https://jvns.ca/blog/2022/02/14/some-dns-terminology/</a></li>
    </ul>
  </li>
  <li>ChatGPT</li>
</ul>

<p>During this challenge I found extremely helpful pairing with ChatGPT, when using binary protocols having a <code>machine</code> that talk that language is key to dealing with problems and weird behaviors, but be careful using it if you are not sure about what you are doing, sometimes it allucinates and generates funny things. 🥸</p>

      ]]></content:encoded>
    </item><item>
      <title>May 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/05/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/05/01/bookmarks.html</guid>
      <pubDate>Wed, 01 May 2024 00:00:00 +0200</pubDate><description>Bookmarks for May 2024: 11 links - How to be an amateur polyglot — LessWrong; App Modernisation — Just Do It. As a consu..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://www.lesswrong.com/posts/BPpeBH8brSCRvZajs/how-to-be-an-amateur-polyglot">How to be an amateur polyglot — LessWrong</a></li>
  <li><a href="https://paul-the-kelly.medium.com/app-modernisation-just-do-it-73f644146c2f">App Modernisation — Just Do It. As a consultant at Pivotal and then… - by Paul Kelly - May, 2024 - Medium</a></li>
  <li><a href="https://www.youtube.com/watch?v=tP9Xnxzwotk">Lesson 135 - Scalability Revisited - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=trmwHdumBrs">Lesson 169 - Atomic vs Eventual Transactions - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=yK9b1C97ct0">Lesson 130 - Frozen Caveman AntiPattern - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=I47J2I-SVi0">Lesson 109 - BASE Transactions and Eventual Consistency - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=AhcFZ8LzKJ8">Lesson 70 - Preventing Data Loss When Using Messaging - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=WzHgOl3xvu4">Distributed Logging System Design - Distributed Logging in Microservices - Systems Design Interview - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=ak1wTYq_opQ">Design a High-Throughput Logging System - System Design - YouTube</a></li>
  <li><a href="https://hazelcast.com/glossary/time-series-database/">What Is A Time Series Database? How It Works &amp; Use Cases - Hazelcast</a></li>
  <li><a href="https://www.rte.ie/brainstorm/2024/0521/1450272-return-to-office-mandates-employees-work-from-home/">You can force employees back to the office, but not the good ones</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>April 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/04/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/04/01/bookmarks.html</guid>
      <pubDate>Mon, 01 Apr 2024 00:00:00 +0200</pubDate><description>Bookmarks for April 2024: 3 links - How I write tests in Go :: Very Good Software, Not Virus; Why you need a &quot;WTF Notebook&quot;; How to boost your metabolism at any age - CNN.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://blog.verygoodsoftwarenotvirus.ru/posts/testing-in-go/">How I write tests in Go :: Very Good Software, Not Virus</a></li>
  <li><a href="https://www.simplermachines.com/why-you-need-a-wtf-notebook/">Why you need a “WTF Notebook”</a></li>
  <li><a href="https://edition.cnn.com/2021/09/24/health/how-to-boost-metabolism-wellness/index.html">How to boost your metabolism at any age - CNN</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>March 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/03/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/03/01/bookmarks.html</guid>
      <pubDate>Fri, 01 Mar 2024 00:00:00 +0100</pubDate><description>Bookmarks for March 2024: 47 links - Timestamp based Concurrency Control - Geek...; ACID Properties in DBMS - GeeksforGeeks, and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://www.geeksforgeeks.org/timestamp-based-concurrency-control/">Timestamp based Concurrency Control - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/acid-properties-in-dbms/">ACID Properties in DBMS - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/concurrency-control-in-dbms/">Concurrency Control in DBMS - GeeksforGeeks</a></li>
  <li><a href="https://www.educative.io/answers/whats-the-difference-between-optimistic-and-pessimistic-locking">What’s the difference between optimistic and pessimistic locking?</a></li>
  <li><a href="https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/">The Law of Leaky Abstractions – Joel on Software</a></li>
  <li><a href="https://martinfowler.com/eaaCatalog/coarseGrainedLock.html">P of EAA: Coarse-Grained Lock</a></li>
  <li><a href="https://martinfowler.com/eaaCatalog/pessimisticOfflineLock.html">P of EAA: Pessimistic Offline Lock</a></li>
  <li><a href="https://martinfowler.com/eaaCatalog/money.html">P of EAA: Money</a></li>
  <li><a href="https://www.geeksforgeeks.org/two-phase-locking-protocol/">Two Phase Locking Protocol - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/concurrency-problems-in-dbms-transactions/">Concurrency problems in DBMS Transactions - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/deadlock-in-dbms/?ref=ml_lbp">Deadlock in DBMS - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/transaction-isolation-levels-dbms/">Transaction Isolation Levels in DBMS - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/what-is-snapshot-isolation/">What is Snapshot Isolation? - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/data-isolation-in-dbms/">Data Isolation in DBMS - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/transaction-in-dbms/">Transaction in DBMS - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/snapshot-isolation-vs-serializable/">Snapshot Isolation vs Serializable - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/commonly-asked-dbms-interview-questions/">Commonly asked DBMS interview questions - Set 1</a></li>
  <li><a href="https:/https://thwack.solarwinds.com/discussion/149615/an-introduction-to-b-tree-and-hash-indexes-in-postgresql">An Introduction to B-Tree and Hash Indexes in PostgreSQL - Data Driven Blog - Data Driven - THWACK</a></li>
  <li><a href="https://www.geeksforgeeks.org/java-multithreading-program-with-example/">Java Multithreading Program with Example - GeeksforGeeks</a></li>
  <li><a href="https://www.baeldung.com/cs/deadlock-livelock-starvation#:~:text=Although%20similar%20in%20nature%2C%20deadlock,change%20their%20resource%20state%20continuously.">Deadlock, Livelock and Starvation - Baeldung on Computer Science</a></li>
  <li><a href="https://www.datasciencecentral.com/developing-multi-threaded-applications-with-java-concurrency-api/#:~:text=Java%20Concurrency%20API%20is%20a,and%20parallel%20code%20in%20Java.">Developing Multi-Threaded Applications with Java Concurrency API</a></li>
  <li><a href="https://www.baeldung.com/java-synchronized">Guide to the Synchronized Keyword in Java - Baeldung</a></li>
  <li><a href="https://www.baeldung.com/java-copy-on-write-arraylist">Guide to CopyOnWriteArrayList - Baeldung</a></li>
  <li><a href="https://www.geeksforgeeks.org/copyonwritearraylist-in-java/">CopyOnWriteArrayList in Java - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/difference-arraylist-copyonwritearraylist/">Difference between ArrayList and CopyOnWriteArrayList - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/difference-between-synchronized-arraylist-and-copyonwritearraylist-in-java-collection/?ref=lbp">Difference Between Synchronized ArrayList and CopyOnWriteArrayList in Java Collection - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/difference-between-lock-and-monitor-in-java-concurrency/?ref=header_search">Difference Between Lock and Monitor in Java Concurrency - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/java-util-concurrent-package/?ref=header_search">java.util.concurrent Package - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/semaphore-in-java/">Semaphore in Java - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/java-util-concurrent-cyclicbarrier-java/">Java.util.concurrent.CyclicBarrier in Java - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/concurrenthashmap-in-java/?ref=header_search">ConcurrentHashMap in Java - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/difference-between-concurrency-and-parallelism/?ref=header_search">Difference between Concurrency and Parallelism - GeeksforGeeks</a></li>
  <li><a href="https://jack-vanlightly.com/blog/2022/1/25/write-for-others-but-mostly-for-yourself">Write for others but mostly for yourself — Jack Vanlightly</a></li>
  <li><a href="https://web.archive.org/web/20220331063644/https://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones">Scalability for Dummies - Part 1: Clones</a></li>
  <li><a href="https://web.archive.org/web/20220602114024/https://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database">Scalability for Dummies - Part 2: Database</a></li>
  <li><a href="https://web.archive.org/web/20230126233752/https://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache">Scalability for Dummies - Part 3: Cache</a></li>
  <li><a href="https://www.youtube.com/watch?v=9SSvdLnmDiI">Lesson 111 - CAP Theorem Illustrated - YouTube</a></li>
  <li><a href="https://superuser.com/questions/472695/who-controls-the-dns-servers/472729">networking - Who controls the DNS servers? - Super User</a></li>
  <li><a href="https://www.tryexponent.com/blog/system-design-interview-guide">Complete System Design Interview Guide - Exponent</a></li>
  <li><a href="https://systemdesign.one/back-of-the-envelope/">Back of the Envelope - System Design</a></li>
  <li><a href="https://blog.dreamfactory.com/what-is-idempotency/#Methods">What is Idempotency? - DreamFactory Software- Blog</a></li>
  <li><a href="https://thenewstack.io/techniques-for-scaling-applications-with-a-database/">Techniques for Scaling Applications with a Database - The New Stack</a></li>
  <li><a href="https://www.youtube.com/watch?v=zFSuV-S3Pws">Lesson 148 - The Fallacies of Compensating Updates - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=I47J2I-SVi0">Lesson 109 - BASE Transactions and Eventual Consistency - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=m2FlZNRELYA">Lesson 94 - Guidelines For Architecture Diagrams - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=g4cmX5ykmjo">Lesson 53 - Distributed Transactions Using Sagas - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=HzJfBorKlLY">Lesson 149 - Caching and CAP Theorem - YouTube</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>Create an application layer load balancer with Golang</title>
      <link>https://domenicoluciani.com/2024/02/12/creating-an-application-layer-load-balancer.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/02/12/creating-an-application-layer-load-balancer.html</guid>
      <pubDate>Mon, 12 Feb 2024 00:00:00 +0100</pubDate><description>Since the last time I had too much fun, I wanted to repeat the experiment by taking another Coding Challenge. This time I&apos;m gonna explain how I implemented an Application Load…</description>
      <content:encoded><![CDATA[
<p>Since the last time I had too much fun, I wanted to <a href="https://domenicoluciani.com/2024/01/29/creating-a-word-count-clone-with-golang.html">repeat the experiment by taking another Coding Challenge</a>. This time I’m gonna explain how I implemented an Application Load Balancer in Golang. <br />
Let’s go! 🚀</p>

<h2 id="application-layer-load-balancer">Application Layer Load Balancer</h2>

<p>Let’s start by describing what is an Application Layer Load Balancer which is important to understand what it does and where are the complexities behind implementing it.</p>

<blockquote>
  <p>Usually a Load Balancer sits in front of a group of servers and routes client requests across all of the servers that are capable of fulfilling those requests.</p>
</blockquote>

<p>Load Balancers ensure that the traffic is equally distributed between our healthy servers minimising the response time.</p>

<p>There are different types of load balancers, they can work at different levels of the <a href="https://en.wikipedia.org/wiki/OSI_model#Layer_architecture">OSI</a>. In this case, I’m gonna be focusing on layer seven of the stack, which will route HTTP requests from clients to a pool of HTTP servers.</p>

<h3 id="functionalities">Functionalities</h3>

<ul>
  <li>Distributes client requests efficiently across multiple servers</li>
  <li>Ensures high availability and reliability by sending requests only to servers that are online</li>
</ul>

<pre><code class="language-mermaid">flowchart TD
subgraph front
Client &lt;--&gt; LoadBalancer
end
subgraph back
LoadBalancer &lt;-.-&gt; Server1 &amp; Server2 &amp; Server3
end
</code></pre>

<h3 id="goals-of-this-challenge">Goals of this challenge</h3>

<ul>
  <li>Build a load balancer that can forward traffic to two or more servers.</li>
  <li>Health check the servers</li>
  <li>Handle a server going offline</li>
  <li>Handle a server coming back online</li>
</ul>

<h2 id="preface">Preface</h2>

<p>Just a friendly reminder that the process I took can be avoided, improved, and of course, wrong. <br />
I’m just telling my story and my Golang-improving journey through this post. <br />
Feel free to give me feedback about it and, if it makes you learn something new or reflect on a topic you never thought about, just let me know ☀️</p>

<h2 id="first-requirement-creating-a-simple-request-forwarder">First Requirement: Creating a simple request forwarder</h2>

<p>First of all, I needed to create a simple server, Golang is very powerful and it allows you to do so in a few steps.</p>

<p>In the main for example, we can have:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">writer</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">request</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Received request from %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">RemoteAddr</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s / %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Proto</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s / %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Proto</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Host: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Host</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"User-Agent: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="s">"User-Agent"</span><span class="p">))</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Accept: %+v</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="s">"Accept"</span><span class="p">))</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Replied with a hello message</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Fprintf</span><span class="p">(</span><span class="n">writer</span><span class="p">,</span> <span class="s">"Hello From Backend Server"</span><span class="p">)</span>  
<span class="p">})</span>  
<span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":80"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>  
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>  
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="s">"Error listening and serve"</span><span class="p">)</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And once run we will have our small server listening at the <code>80</code> port, logging each request that has been received at the <code>/</code> endpoint.</p>

<p>To verify it you can just call <code>curl http://localhost/ --output -</code> having as a result: <code>Hello From Backend Server</code>.</p>

<p>Of course, it’s not enough to have a service that forwards our requests to specified servers but it’s a start to understand how Golang works.</p>

<p>So to get back to our problem, I started with a unit test:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"should call the client to forward the request"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">req</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">NewRequest</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="s">"/"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>  
    <span class="n">resp</span> <span class="o">:=</span> <span class="n">httptest</span><span class="o">.</span><span class="n">NewRecorder</span><span class="p">()</span>  
    <span class="n">mockClient</span> <span class="o">:=</span> <span class="n">newMockClient</span><span class="p">()</span>  
    <span class="n">spartimillu</span> <span class="o">:=</span> <span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">mockClient</span><span class="p">)</span>  
    <span class="n">mockClient</span><span class="o">.</span><span class="n">On</span><span class="p">(</span><span class="s">"ForwardRequest"</span><span class="p">,</span> <span class="n">mock</span><span class="o">.</span><span class="n">Anything</span><span class="p">)</span><span class="o">.</span><span class="n">Return</span><span class="p">(</span><span class="o">&amp;</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span><span class="p">{</span>  
       <span class="n">Status</span><span class="o">:</span>     <span class="s">"200 OK"</span><span class="p">,</span>  
       <span class="n">StatusCode</span><span class="o">:</span> <span class="m">200</span><span class="p">,</span>  
       <span class="n">Proto</span><span class="o">:</span>      <span class="s">"HTTP/1.0"</span><span class="p">,</span>  
       <span class="n">Body</span><span class="o">:</span>       <span class="n">io</span><span class="o">.</span><span class="n">NopCloser</span><span class="p">(</span><span class="n">bytes</span><span class="o">.</span><span class="n">NewBufferString</span><span class="p">(</span><span class="s">"dummy body"</span><span class="p">)),</span>  
       <span class="n">Request</span><span class="o">:</span>    <span class="n">req</span><span class="p">,</span>  
    <span class="p">})</span>  
    <span class="n">spartimillu</span><span class="o">.</span><span class="n">ServeHTTP</span><span class="p">(</span><span class="n">resp</span><span class="p">,</span> <span class="n">req</span><span class="p">)</span>  
  
    <span class="n">mockClient</span><span class="o">.</span><span class="n">AssertExpectations</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"dummy body"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Body</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span> <span class="s">"got %q, want %q"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Body</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span> <span class="s">"dummy body"</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>With this test:</p>

<ul>
  <li>I create a new mockedRequest specifying the method and the endpoint.</li>
  <li>Create some mocked response thanks to the <code>httptest</code> package.</li>
  <li>Create a mocked client.</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">MockClient</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">mock</span><span class="o">.</span><span class="n">Mock</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">newMockClient</span><span class="p">()</span> <span class="o">*</span><span class="n">MockClient</span> <span class="p">{</span> <span class="k">return</span> <span class="o">&amp;</span><span class="n">MockClient</span><span class="p">{}</span> <span class="p">}</span>  
  
<span class="k">func</span> <span class="p">(</span><span class="n">m</span> <span class="o">*</span><span class="n">MockClient</span><span class="p">)</span> <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="n">args</span> <span class="o">:=</span> <span class="n">m</span><span class="o">.</span><span class="n">Called</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>  
    <span class="k">return</span> <span class="n">args</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="m">0</span><span class="p">)</span><span class="o">.</span><span class="p">(</span><span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span><span class="p">)</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="p">(</span><span class="n">m</span> <span class="o">*</span><span class="n">MockClient</span><span class="p">)</span> <span class="n">HealthCheck</span><span class="p">()</span> <span class="p">{</span>  
    <span class="n">m</span><span class="o">.</span><span class="n">Called</span><span class="p">()</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>I provide my mocked client as a parameter for my load balancer server that I called <code>SpartimilluServer</code>.</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">SpartimilluServer</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">client</span> <span class="n">client</span><span class="o">.</span><span class="n">Client</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">client</span> <span class="n">client</span><span class="o">.</span><span class="n">Client</span><span class="p">)</span> <span class="o">*</span><span class="n">SpartimilluServer</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">SpartimilluServer</span><span class="p">{</span><span class="n">client</span><span class="o">:</span> <span class="n">client</span><span class="p">}</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>I mock the <code>ForwardRequest</code> function to return a custom response with <code>dummy body</code> as a body.</li>
  <li>And then call the function under test: <code>ServeHttp</code>.</li>
  <li>Checking that the body of the response that we get back is equal to what we are expecting.</li>
</ul>

<p>The implementation was quite straightforward:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluServer</span><span class="p">)</span> <span class="n">ServeHTTP</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Received request from %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">RemoteAddr</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s / %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Proto</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s / %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Proto</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Host: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Host</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"User-Agent: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="s">"User-Agent"</span><span class="p">))</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Accept: %+v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="s">"Accept"</span><span class="p">))</span>  
  
    <span class="n">resp</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">r</span><span class="p">)</span>  
  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Response from server: %s %s</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Proto</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Status</span><span class="p">)</span>  
  
    <span class="n">body</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">io</span><span class="o">.</span><span class="n">ReadAll</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">Body</span><span class="p">)</span>  
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>  
       <span class="n">http</span><span class="o">.</span><span class="n">Error</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Error reading the response body"</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span><span class="p">)</span>  
    <span class="p">}</span>  
    <span class="n">stringBody</span> <span class="o">:=</span> <span class="kt">string</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Fprint</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">stringBody</span><span class="p">)</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">stringBody</span><span class="p">)</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="forward-request">Forward Request</h3>

<p>Now we need to implement our client and its functionalities.</p>

<p>Let’s start with an integration test!</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"should forward a GET request to a specific server"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">server</span><span class="p">,</span> <span class="n">address</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"ok"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">conf</span> <span class="o">:=</span> <span class="n">NewSpartimilluClientConf</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="n">address</span><span class="p">})</span>  
    <span class="n">client</span> <span class="o">:=</span> <span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">conf</span><span class="p">)</span>  
    <span class="n">req</span> <span class="o">:=</span> <span class="n">httptest</span><span class="o">.</span><span class="n">NewRequest</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="s">"/"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">body</span> <span class="o">:=</span> <span class="n">getBodyFromResp</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">resp</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"ok"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"ok"</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So let’s see what is happening here:</p>
<ul>
  <li>Golang gives us the fantastic opportunity to spawn up a local stub server with just a few lines of code using the <code>httptest</code> package and defer it with the <code>Close</code> method:</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">startTestServer</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">bodyResponse</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="n">httptest</span><span class="o">.</span><span class="n">Server</span><span class="p">,</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">t</span><span class="o">.</span><span class="n">Helper</span><span class="p">()</span>  
  
    <span class="n">server</span> <span class="o">:=</span> <span class="n">httptest</span><span class="o">.</span><span class="n">NewServer</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">HandlerFunc</span><span class="p">(</span><span class="k">func</span><span class="p">(</span><span class="n">writer</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">request</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s has been called</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bodyResponse</span><span class="p">)</span>  
       <span class="n">fmt</span><span class="o">.</span><span class="n">Fprint</span><span class="p">(</span><span class="n">writer</span><span class="p">,</span> <span class="n">bodyResponse</span><span class="p">)</span>  
    <span class="p">}))</span>    
    <span class="k">return</span> <span class="n">server</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">URL</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see we are using the <code>NewServer</code> method to spawn up a new server and then set a handler function to get back some info.</p>

<ul>
  <li>I wanted to have flexibility in terms of configuration so I created a <code>SpartimilluClientConf</code> struct:</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">SpartimilluClientConf</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">addresses</span>           <span class="p">[]</span><span class="kt">string</span>
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">NewSpartimilluClientConf</span><span class="p">(</span><span class="n">addresses</span> <span class="p">[]</span><span class="kt">string</span><span class="p">)</span> <span class="n">SpartimilluClientConf</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="n">SpartimilluClientConf</span><span class="p">{</span><span class="n">addresses</span><span class="o">:</span> <span class="n">addresses</span><span class="p">}</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see it just contains some info like addresses and the health-check endpoint (we will get there later).</p>

<ul>
  <li>I created the client passing the conf as a dependency</li>
  <li>Then call the <code>ForwardRequest</code> method passing the request I created.</li>
  <li>Some assertions, to verify that everything is as expected.   For example to read the body:
    <div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">getBodyFromResp</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">resp</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>  
  <span class="n">t</span><span class="o">.</span><span class="n">Helper</span><span class="p">()</span>  
  
  <span class="n">bodyBytes</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">io</span><span class="o">.</span><span class="n">ReadAll</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">Body</span><span class="p">)</span>  
  <span class="n">assert</span><span class="o">.</span><span class="n">Nil</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>  
  <span class="k">return</span> <span class="kt">string</span><span class="p">(</span><span class="n">bodyBytes</span><span class="p">)</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
</ul>

<p>To then jump into the implementation:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Client</span> <span class="k">interface</span> <span class="p">{</span>  
    <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span>  
<span class="p">}</span>  
  
<span class="k">type</span> <span class="n">SpartimilluClient</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">conf</span> <span class="n">SpartimilluClientConf</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">conf</span> <span class="n">SpartimilluClientConf</span><span class="p">)</span> <span class="o">*</span><span class="n">SpartimilluClient</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">SpartimilluClient</span><span class="p">{</span><span class="n">conf</span><span class="o">:</span> <span class="n">conf</span><span class="p">}</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluClient</span><span class="p">)</span> <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="k">switch</span> <span class="n">req</span><span class="o">.</span><span class="n">Method</span> <span class="p">{</span>  
    <span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="o">:</span>  
       <span class="k">return</span> <span class="n">sendGetRequestToAnotherServer</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">address</span> <span class="o">+</span> <span class="n">req</span><span class="o">.</span><span class="n">RequestURI</span><span class="p">)</span>
    <span class="p">}</span>    
    <span class="k">return</span> <span class="no">nil</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">sendGetRequestToAnotherServer</span><span class="p">(</span><span class="n">url</span> <span class="kt">string</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="n">body</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>  
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>  
       <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="s">"Can't read the response body from the GET request"</span><span class="p">)</span>  
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">body</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see I just called the <code>http.Get(url)</code> method emulating the <code>GET</code> request we got.</p>

<h3 id="try-it-out">Try it out</h3>

<p>To see everything in action we can just call our main:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>  
    <span class="n">spartimilluClient</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClientConf</span><span class="p">(</span><span class="s">"http://localhost:8080"</span><span class="p">))</span>  
    <span class="n">spartimilluServer</span> <span class="o">:=</span> <span class="n">server</span><span class="o">.</span><span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">spartimilluClient</span><span class="p">)</span>  
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":80"</span><span class="p">,</span> <span class="n">spartimilluServer</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>In this case I spawned up a separate server listening at the port <code>8080</code> and provided it into the configuration.</li>
  <li>Then created my <code>SpartimilluServer</code> function handler and used it for my <code>ListenAndServe</code> function.</li>
</ul>

<p>To spawn up my little server you can use a different main with the code you saw before or just create a directory called for example <code>server8080</code> containing an <code>index.html</code> file with this content:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="cp">&lt;!DOCTYPE html&gt;</span>  
<span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>  
    <span class="nt">&lt;head&gt;</span>  
       <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>  
       <span class="nt">&lt;title&gt;</span>Index Page<span class="nt">&lt;/title&gt;</span>  
    <span class="nt">&lt;/head&gt;</span>  
    <span class="nt">&lt;body&gt;</span>  
       Hello from the web server running on port 8080.  
    <span class="nt">&lt;/body&gt;</span>  
<span class="nt">&lt;/html&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and run in your terminal: <code>python -m http.server 8080 --directory server8080</code>, it will spawn up a python server serving the content of the directory <code>directory8080</code>.</p>

<p>So then you can just call your young load balancer: <code>curl http://localhost/ --output -</code>.</p>

<p>The result will be:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>❯ curl http://localhost/ <span class="nt">--output</span> -
&lt;<span class="o">!</span>DOCTYPE html&gt;
&lt;html <span class="nv">lang</span><span class="o">=</span><span class="s2">"en"</span><span class="o">&gt;</span>
	&lt;<span class="nb">head</span><span class="o">&gt;</span>
		&lt;meta <span class="nv">charset</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="o">&gt;</span>
		&lt;title&gt;Index Page&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		Hello from the web server running on port 8080.
	&lt;/body&gt;
&lt;/html&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<pre><code class="language-mermaid">flowchart TD
subgraph front
CURL --"1. GET index.html"--&gt; SpartimilluServer
SpartimilluServer --"4. index.html"--&gt; CURL
end
subgraph back
SpartimilluServer-. "2. GET index.html" .-&gt; PythonServer8080
PythonServer8080-. "3. index.html" .-&gt; SpartimilluServer
end
</code></pre>

<h2 id="second-requirement-distribute-traffic-with-round-robin">Second Requirement: Distribute traffic with Round Robin</h2>

<p>Now that we have our “forwarder” in place, we have to distribute the incoming requests using a scheduling algorithm called “Round Robin”. <br />
It’s quite simple, we just need to distribute the traffic to each server in the list, one after the other and once forwarded to all of them we start back at the beginning of the list.</p>

<p>For example:</p>

<table>
  <thead>
    <tr>
      <th>Server</th>
      <th>Request</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A</td>
      <td>1, 4</td>
    </tr>
    <tr>
      <td>B</td>
      <td>2, 5</td>
    </tr>
    <tr>
      <td>C</td>
      <td>3, 6</td>
    </tr>
  </tbody>
</table>

<p>Let’s start with another integration test:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"should forward a GET request to any server using a round robin algorithm"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">server1</span><span class="p">,</span> <span class="n">address1</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"server1"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server1</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">server2</span><span class="p">,</span> <span class="n">address2</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"server2"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server2</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">server3</span><span class="p">,</span> <span class="n">address3</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"server3"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server3</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">conf</span> <span class="o">:=</span> <span class="n">NewSpartimilluClientConf</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="n">address1</span><span class="p">,</span> <span class="n">address2</span><span class="p">,</span> <span class="n">address3</span><span class="p">})</span>  
    <span class="n">client</span> <span class="o">:=</span> <span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">conf</span><span class="p">)</span>  
    <span class="n">req</span> <span class="o">:=</span> <span class="n">httptest</span><span class="o">.</span><span class="n">NewRequest</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="s">"/"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">body</span> <span class="o">:=</span> <span class="n">getBodyFromResp</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">resp</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"server1"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"server1"</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">body</span> <span class="o">=</span> <span class="n">getBodyFromResp</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">resp</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"server2"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"server2"</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">body</span> <span class="o">=</span> <span class="n">getBodyFromResp</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">resp</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s">"server3"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="s">"server3"</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We spawn up 3 servers and set their address in our configuration.</p>
<ol>
  <li>We call ForwardRequest</li>
  <li>We expect to contact and then receive an answer from the <code>sever1</code></li>
  <li>We call again ForwardRequest</li>
  <li>We expect to contact and then receive an answer from the <code>server2</code>.</li>
  <li>We call again ForwardRequest</li>
  <li>We expect to contact and then receive an answer from the <code>server3</code>.</li>
</ol>

<p>Let’s jump into the implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">SpartimilluClient</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">conf</span>    <span class="n">SpartimilluClientConf</span>  
    <span class="n">counter</span> <span class="kt">int</span>  
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluClient</span><span class="p">)</span> <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="k">var</span> <span class="n">resp</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span>  
  
    <span class="n">serverIndex</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">counter</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span><span class="p">)</span>  
  
    <span class="k">switch</span> <span class="n">req</span><span class="o">.</span><span class="n">Method</span> <span class="p">{</span>  
    <span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="o">:</span>  
       <span class="n">resp</span> <span class="o">=</span> <span class="n">sendGetRequestToAnotherServer</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span><span class="p">[</span><span class="n">serverIndex</span><span class="p">]</span> <span class="o">+</span> <span class="n">req</span><span class="o">.</span><span class="n">RequestURI</span><span class="p">)</span>   
    <span class="p">}</span>  
    <span class="n">s</span><span class="o">.</span><span class="n">counter</span><span class="o">++</span>  
  
    <span class="k">return</span> <span class="n">resp</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using a counter <code>counter</code> and the <a href="https://en.wikipedia.org/wiki/Modulo">module operator</a> I implemented a simple round-robin algorithm.</p>

<p>Let’s see how it works:</p>

<table>
  <thead>
    <tr>
      <th>counter</th>
      <th>operation</th>
      <th>serverIndex</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>0 % 3</td>
      <td>0</td>
    </tr>
    <tr>
      <td>1</td>
      <td>1 % 3</td>
      <td>1</td>
    </tr>
    <tr>
      <td>2</td>
      <td>2 % 3</td>
      <td>2</td>
    </tr>
    <tr>
      <td>3</td>
      <td>3 % 3</td>
      <td>0</td>
    </tr>
    <tr>
      <td>4</td>
      <td>4 % 3</td>
      <td>1</td>
    </tr>
    <tr>
      <td>5</td>
      <td>5 % 3</td>
      <td>2</td>
    </tr>
    <tr>
      <td>6</td>
      <td>6 % 3</td>
      <td>0</td>
    </tr>
    <tr>
      <td>…</td>
      <td>…</td>
      <td>…</td>
    </tr>
  </tbody>
</table>

<p>And so on. 🤯</p>

<h3 id="try-it-out-1">Try it out</h3>

<p>Our main should look like this:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>  
    <span class="n">spartimilluClient</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClientConf</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span>  
       <span class="s">"http://localhost:8080"</span><span class="p">,</span>  
       <span class="s">"http://localhost:8081"</span><span class="p">,</span>  
    <span class="p">}))</span>
    <span class="n">spartimilluServer</span> <span class="o">:=</span> <span class="n">server</span><span class="o">.</span><span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">spartimilluClient</span><span class="p">)</span>  
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":80"</span><span class="p">,</span> <span class="n">spartimilluServer</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see we specified 2 addresses in our configuration, a server listening at <code>8080</code> and one listening at <code>8081</code>.</p>

<p>Of course, before starting our load balancer we should spawn up our servers.</p>

<p>Let’s create a directory (as we did before for the <code>server8080</code>) but this time called <code>server8081</code> inside an <code>index.html</code> containing something similar:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="cp">&lt;!DOCTYPE html&gt;</span>  
<span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>  
    <span class="nt">&lt;head&gt;</span>  
       <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>  
       <span class="nt">&lt;title&gt;</span>Index Page<span class="nt">&lt;/title&gt;</span>  
    <span class="nt">&lt;/head&gt;</span>  
    <span class="nt">&lt;body&gt;</span>  
       Hello from the web server running on port 8081.  
    <span class="nt">&lt;/body&gt;</span>  
<span class="nt">&lt;/html&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we can just run these commands in 2 different shells:</p>

<ol>
  <li>server8080: <code>python -m http.server 8080 --directory server8080</code></li>
  <li>server8081: <code>python -m http.server 8081 --directory server8081</code></li>
</ol>

<p>Once both servers are up we can test it out just executing our main and calling our load balancer three times to see how it works:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>❯ curl http://localhost/ <span class="nt">--output</span> -
&lt;<span class="o">!</span>DOCTYPE html&gt;
&lt;html <span class="nv">lang</span><span class="o">=</span><span class="s2">"en"</span><span class="o">&gt;</span>
	&lt;<span class="nb">head</span><span class="o">&gt;</span>
		&lt;meta <span class="nv">charset</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="o">&gt;</span>
		&lt;title&gt;Index Page&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		Hello from the web server running on port 8080.
	&lt;/body&gt;
&lt;/html&gt;
</pre></td></tr></tbody></table></code></pre></div></div>
<p>and</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>❯ curl http://localhost/ <span class="nt">--output</span> -
&lt;<span class="o">!</span>DOCTYPE html&gt;
&lt;html <span class="nv">lang</span><span class="o">=</span><span class="s2">"en"</span><span class="o">&gt;</span>
	&lt;<span class="nb">head</span><span class="o">&gt;</span>
		&lt;meta <span class="nv">charset</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="o">&gt;</span>
		&lt;title&gt;Index Page&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		Hello from the web server running on port 8081.
	&lt;/body&gt;
&lt;/html&gt;
</pre></td></tr></tbody></table></code></pre></div></div>
<p>and</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>❯ curl http://localhost/ <span class="nt">--output</span> -
&lt;<span class="o">!</span>DOCTYPE html&gt;
&lt;html <span class="nv">lang</span><span class="o">=</span><span class="s2">"en"</span><span class="o">&gt;</span>
	&lt;<span class="nb">head</span><span class="o">&gt;</span>
		&lt;meta <span class="nv">charset</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="o">&gt;</span>
		&lt;title&gt;Index Page&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		Hello from the web server running on port 8080.
	&lt;/body&gt;
&lt;/html&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<pre><code class="language-mermaid">flowchart TD
subgraph front
CURL --"1. GET index.html"--&gt; SpartimilluServer
SpartimilluServer --"4/6. index.html"--&gt; CURL
end
subgraph back
SpartimilluServer-. "2. GET index.html" .-&gt; PythonServer8080
PythonServer8080-. "3. index.html" .-&gt; SpartimilluServer
SpartimilluServer-. "4. GET index.html" .-&gt; PythonServer8081
PythonServer8081-. "5. index.html" .-&gt; SpartimilluServer
end
</code></pre>

<h2 id="third-requirement-implement-a-health-check">Third Requirement: Implement a Health Check</h2>

<p>Now that we implemented the main functionality we have to implement the health check that helps us to always forward the request to a live server.</p>

<p>Let’s start with a unit test:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"should call the client to do an health check"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">req</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">NewRequest</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="s">"/healthcheck"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>  
    <span class="n">resp</span> <span class="o">:=</span> <span class="n">httptest</span><span class="o">.</span><span class="n">NewRecorder</span><span class="p">()</span>  
    <span class="n">mockClient</span> <span class="o">:=</span> <span class="n">newMockClient</span><span class="p">()</span>  
    <span class="n">spartimillu</span> <span class="o">:=</span> <span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">mockClient</span><span class="p">)</span>  
    <span class="n">mockClient</span><span class="o">.</span><span class="n">On</span><span class="p">(</span><span class="s">"HealthCheck"</span><span class="p">)</span><span class="o">.</span><span class="n">Return</span><span class="p">(</span><span class="o">&amp;</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span><span class="p">{</span>  
       <span class="n">Status</span><span class="o">:</span>     <span class="s">"200 OK"</span><span class="p">,</span>  
       <span class="n">StatusCode</span><span class="o">:</span> <span class="m">200</span><span class="p">,</span>  
       <span class="n">Proto</span><span class="o">:</span>      <span class="s">"HTTP/1.0"</span><span class="p">,</span>  
       <span class="n">Request</span><span class="o">:</span>    <span class="n">req</span><span class="p">,</span>  
    <span class="p">})</span>  
    <span class="n">spartimillu</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
  
    <span class="n">mockClient</span><span class="o">.</span><span class="n">AssertExpectations</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Code</span><span class="p">,</span> <span class="s">"got %q, want %q"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Code</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">MockClient</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">mock</span><span class="o">.</span><span class="n">Mock</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">newMockClient</span><span class="p">()</span> <span class="o">*</span><span class="n">MockClient</span> <span class="p">{</span> <span class="k">return</span> <span class="o">&amp;</span><span class="n">MockClient</span><span class="p">{}</span> <span class="p">}</span>  
  
<span class="k">func</span> <span class="p">(</span><span class="n">m</span> <span class="o">*</span><span class="n">MockClient</span><span class="p">)</span> <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="n">args</span> <span class="o">:=</span> <span class="n">m</span><span class="o">.</span><span class="n">Called</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>  
    <span class="k">return</span> <span class="n">args</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="m">0</span><span class="p">)</span><span class="o">.</span><span class="p">(</span><span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span><span class="p">)</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="p">(</span><span class="n">m</span> <span class="o">*</span><span class="n">MockClient</span><span class="p">)</span> <span class="n">HealthCheck</span><span class="p">()</span> <span class="p">{</span>  
    <span class="n">m</span><span class="o">.</span><span class="n">Called</span><span class="p">()</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As we have done before we are checking that the method <code>HealthCheck</code> has been implemented correctly in our <code>SpartimilluServer</code>.</p>

<p>With a very simple implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluServer</span><span class="p">)</span> <span class="n">HealthCheck</span><span class="p">()</span> <span class="p">{</span>  
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Performing Health Check</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>  
  
    <span class="n">s</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This method would be called every N seconds to check if our servers are still alive.</p>

<p>As usual, let’s continue with an integration test for our client:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"should perform a health check towards a server"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">server1</span><span class="p">,</span> <span class="n">address1</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="s">"server1"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server1</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">server2</span><span class="p">,</span> <span class="n">address2</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="s">"server2"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server2</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">server3</span><span class="p">,</span> <span class="n">address3</span> <span class="o">:=</span> <span class="n">startTestServer</span><span class="p">(</span><span class="s">"server3"</span><span class="p">)</span>  
    <span class="k">defer</span> <span class="n">server3</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
  
    <span class="n">conf</span> <span class="o">:=</span> <span class="n">NewSpartimilluClientConf</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="n">address1</span><span class="p">,</span> <span class="n">address2</span><span class="p">,</span> <span class="n">address3</span><span class="p">},</span> <span class="s">"/healthcheck"</span><span class="p">)</span>  
    <span class="n">client</span> <span class="o">:=</span> <span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">conf</span><span class="p">)</span>  
    <span class="n">req</span> <span class="o">:=</span> <span class="n">httptest</span><span class="o">.</span><span class="n">NewRequest</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="p">,</span> <span class="s">"/"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>  
  
    <span class="n">client</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
    <span class="n">resp</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">server1</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">server1</span><span class="o">.</span><span class="n">URL</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">server2</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">server2</span><span class="o">.</span><span class="n">URL</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">server3</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">server3</span><span class="o">.</span><span class="n">URL</span><span class="p">)</span>  
  
    <span class="n">server1</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
  
    <span class="n">client</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">server2</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">server2</span><span class="o">.</span><span class="n">URL</span><span class="p">)</span>  
  
    <span class="n">server2</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
    <span class="n">client</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">server3</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">server3</span><span class="o">.</span><span class="n">URL</span><span class="p">)</span>  
  
    <span class="n">resp</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="o">*</span><span class="n">req</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">server3</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="s">"got %v, wanted %v"</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Scheme</span><span class="o">+</span><span class="s">"://"</span><span class="o">+</span><span class="n">resp</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">server3</span><span class="o">.</span><span class="n">URL</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s see what we did:</p>

<ul>
  <li>As usual, we spawned up 3 servers adding them to our servers list</li>
  <li>We call our <code>HealthCheck</code> method that supposed to update our list of available servers</li>
  <li>We call the <code>ForwardRequest</code> method checking then if we contact the right server.</li>
  <li>The first 3 times we checked if we had contacted iteratively each server.</li>
  <li>We shut down the <code>server1</code></li>
  <li>We re-do the health-check</li>
  <li>We re-call our <code>ForwardRequest</code> method but this time our method should call the <code>server2</code> since the server1 has been shut down.</li>
  <li>We do the same thing then for the <code>server2</code>, expecting then to call the only one left <code>server3</code>.</li>
</ul>

<p>Here is the implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Client</span> <span class="k">interface</span> <span class="p">{</span>  
    <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span>  
    <span class="n">HealthCheck</span><span class="p">()</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">SpartimilluClient</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">conf</span>           <span class="n">SpartimilluClientConf</span>  
    <span class="n">counter</span>        <span class="kt">int</span>  
    <span class="n">healthyServers</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">bool</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We added to our struct a map of healthyServers that will be updated by our <code>HealthCheck</code> method.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">conf</span> <span class="n">SpartimilluClientConf</span><span class="p">)</span> <span class="o">*</span><span class="n">SpartimilluClient</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">SpartimilluClient</span><span class="p">{</span><span class="n">conf</span><span class="o">:</span> <span class="n">conf</span><span class="p">,</span> <span class="n">healthyServers</span><span class="o">:</span> <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">bool</span><span class="p">)}</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluClient</span><span class="p">)</span> <span class="n">HealthCheck</span><span class="p">()</span> <span class="p">{</span>  
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">address</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span> <span class="p">{</span>  
       <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>  
       <span class="k">if</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="o">&amp;&amp;</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span> <span class="o">==</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span> <span class="p">{</span>  
          <span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">[</span><span class="n">address</span><span class="p">]</span> <span class="o">=</span> <span class="no">true</span>  
       <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>  
          <span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">[</span><span class="n">address</span><span class="p">]</span> <span class="o">=</span> <span class="no">false</span>  
       <span class="p">}</span>  
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We iterate over the list of addresses and for each server we do a GET request to check if we got an OK, if so we update our healthyServers map having as a key the address and a boolean value as a value.</p>

<p>And this is the implementation of our <code>ForwardRequest</code> method:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluClient</span><span class="p">)</span> <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>  
       <span class="n">s</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
    <span class="p">}</span>  
    <span class="n">index</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">counter</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span><span class="p">)</span>  
    <span class="n">address</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>  
    <span class="n">s</span><span class="o">.</span><span class="n">counter</span><span class="o">++</span>  
  
    <span class="k">if</span> <span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">[</span><span class="n">address</span><span class="p">]{</span>  
       <span class="k">switch</span> <span class="n">req</span><span class="o">.</span><span class="n">Method</span> <span class="p">{</span>  
       <span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="o">:</span>  
          <span class="k">return</span> <span class="n">sendGetRequestToAnotherServer</span><span class="p">(</span><span class="n">address</span> <span class="o">+</span> <span class="n">req</span><span class="o">.</span><span class="n">RequestURI</span><span class="p">)</span>
      <span class="p">}</span>    
   <span class="p">}</span>  
   <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we make sure that we perform a health check at least once before we start forwarding requests around. <br />
Then we check if the server we want to contact is healthy then we contact it otherwise we do a recursive call to call the next one in the list. <br />
The recursion is not very efficient but it works nicely for now, we will improve it in the next step.</p>

<h3 id="try-it-out-2">Try it out</h3>

<p>Our main now looks like this:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">spartimilluClient</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClientConf</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span>  
       <span class="s">"http://localhost:8080"</span><span class="p">,</span>  
       <span class="s">"http://localhost:8081"</span><span class="p">,</span>  
    <span class="p">},</span> <span class="s">"/healthcheck"</span><span class="p">))</span>  
   <span class="n">spartimilluServer</span> <span class="o">:=</span> <span class="n">server</span><span class="o">.</span><span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">spartimilluClient</span><span class="p">)</span>  
  
  <span class="n">ticker</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">NewTicker</span><span class="p">(</span><span class="m">5</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
  <span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">for</span> <span class="p">{</span>  
          <span class="k">select</span> <span class="p">{</span>  
          <span class="k">case</span> <span class="o">&lt;-</span><span class="n">ticker</span><span class="o">.</span><span class="n">C</span><span class="o">:</span>  
             <span class="n">spartimilluServer</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
          <span class="p">}</span>       
      <span class="p">}</span>
  <span class="p">}()</span>
  <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":80"</span><span class="p">,</span> <span class="n">spartimilluServer</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is the first raw version of our async HealtCheck. <br />
We call asynchronously our <code>HealthCheck</code> every 5 seconds using a <code>ticker</code>.</p>

<p>To try it out we can reproduce the steps above spawning our 2 stubbed servers and once we run our load-balancer we can just kill one of the two to check if our load-balancer every 5 seconds decides to contact the only one that is still alive.</p>

<pre><code class="language-mermaid">flowchart TD
subgraph front
CURL --"1. GET index.html"--&gt; SpartimilluServer
SpartimilluServer --"4. index.html"--&gt; CURL
end
subgraph back
PythonServer8080
SpartimilluServer-. "2. GET index.html" .-&gt; PythonServer8081
PythonServer8081-. "3. index.html" .-&gt; SpartimilluServer
end
</code></pre>

<h2 id="fighting-concurrency">Fighting concurrency</h2>

<p>Another thing we have to make sure to handle is the concurrency. <br />
As you could have seen our <code>HealthCheck</code> function is modifying a shared map with <code>ForwardRequest</code>, and it can cause concurrency issues since it can be accessed by both functions at the same time. We can do that using a mutex.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">SpartimilluClient</span> <span class="k">struct</span> <span class="p">{</span>  
    <span class="n">conf</span>           <span class="n">SpartimilluClientConf</span>  
    <span class="n">counter</span>        <span class="kt">int</span>  
    <span class="n">healthyServers</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">bool</span>  
    <span class="n">mu</span>             <span class="n">sync</span><span class="o">.</span><span class="n">Mutex</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here is our <code>HealthCheck</code> implementation:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluClient</span><span class="p">)</span> <span class="n">HealthCheck</span><span class="p">()</span> <span class="p">{</span>  
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">address</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span> <span class="p">{</span>  
       <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>  
  
       <span class="n">s</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>  
       <span class="k">if</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="o">&amp;&amp;</span> <span class="n">resp</span><span class="o">.</span><span class="n">StatusCode</span> <span class="o">==</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span> <span class="p">{</span>  
          <span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">[</span><span class="n">address</span><span class="p">]</span> <span class="o">=</span> <span class="no">true</span>  
       <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>  
          <span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">[</span><span class="n">address</span><span class="p">]</span> <span class="o">=</span> <span class="no">false</span>  
       <span class="p">}</span>  
       <span class="n">s</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>  
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Every time we want to access our <code>healthyServers</code> map we lock it down to be sure that anybody else can do it before releasing it back.</p>

<p>And the <code>ForwardRequest</code>one:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">SpartimilluClient</span><span class="p">)</span> <span class="n">ForwardRequest</span><span class="p">(</span><span class="n">req</span> <span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Response</span> <span class="p">{</span>  
    <span class="k">for</span> <span class="p">{</span>  
       <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>  
          <span class="n">s</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">()</span>  
       <span class="p">}</span>  
       <span class="n">s</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>  
       <span class="n">index</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">counter</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span><span class="p">)</span>  
       <span class="n">address</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">addresses</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>  
       <span class="n">s</span><span class="o">.</span><span class="n">counter</span><span class="o">++</span>  
  
       <span class="k">if</span> <span class="n">s</span><span class="o">.</span><span class="n">healthyServers</span><span class="p">[</span><span class="n">address</span><span class="p">]</span> <span class="o">==</span> <span class="no">true</span> <span class="p">{</span>  
          <span class="n">s</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>  
          <span class="k">switch</span> <span class="n">req</span><span class="o">.</span><span class="n">Method</span> <span class="p">{</span>  
          <span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="o">:</span>  
             <span class="k">return</span> <span class="n">sendGetRequestToAnotherServer</span><span class="p">(</span><span class="n">address</span> <span class="o">+</span> <span class="n">req</span><span class="o">.</span><span class="n">RequestURI</span><span class="p">)</span>  
          <span class="p">}</span>       
       <span class="p">}</span>       
      <span class="n">s</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>  
      <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">100</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Millisecond</span><span class="p">)</span>  
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here I did a bit of refactoring and of course, used the <code>Lock</code> to handle concurrency issues. I also removed the recurse for a for/infinite loop with a sleep time to re-try contacting our servers.</p>

<h3 id="try-it-out-3">Try it out</h3>

<p>After a refactoring our main looks like this:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>  
    <span class="k">const</span> <span class="n">seconds</span> <span class="o">=</span> <span class="m">1</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span>  
  
    <span class="n">spartimilluClient</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClient</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">NewSpartimilluClientConf</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span>  
       <span class="s">"http://localhost:8080"</span><span class="p">,</span>  
       <span class="s">"http://localhost:8081"</span><span class="p">,</span>  
    <span class="p">},</span> <span class="s">"/healthcheck"</span><span class="p">))</span>  
    <span class="n">spartimilluServer</span> <span class="o">:=</span> <span class="n">server</span><span class="o">.</span><span class="n">NewSpartimilluServer</span><span class="p">(</span><span class="n">spartimilluClient</span><span class="p">)</span>  
  
    <span class="k">go</span> <span class="n">doEvery</span><span class="p">(</span><span class="n">seconds</span><span class="p">,</span> <span class="n">spartimilluServer</span><span class="o">.</span><span class="n">HealthCheck</span><span class="p">)</span>  
  
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":80"</span><span class="p">,</span> <span class="n">spartimilluServer</span><span class="p">))</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">doEvery</span><span class="p">(</span><span class="n">d</span> <span class="n">time</span><span class="o">.</span><span class="n">Duration</span><span class="p">,</span> <span class="n">f</span> <span class="k">func</span><span class="p">())</span> <span class="p">{</span>  
    <span class="n">ticker</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">Tick</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>  
    <span class="k">for</span> <span class="k">range</span> <span class="n">ticker</span> <span class="p">{</span>  
       <span class="k">go</span> <span class="n">f</span><span class="p">()</span>  
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>A this time you should have your load balancer switching from one server to another and performing health checks correctly.</p>

<h2 id="final-thoughts">Final Thoughts</h2>

<p>It has been a quite fun challenge, iteratively I built up my application load balancer starting from a small forward to then adding a more complex logic facing up some nice challenges like evolving my code to embrace the change and how to do integration tests spawning-up stub servers.</p>

<p>Of course, this is a very basic load balancer, it can be improved and extended but I’m satisfied with it for now.</p>

<p>You can find the repository with the code in my Github profile, <a href="https://github.com/dlion/spartimillu">https://github.com/dlion/spartimillu</a>.</p>

<p>What do you think about my solution? Any feedback would be appreciated and of course, if you make your solution don’t be shy and share it with me too!</p>

<p>Happy Coding!</p>

      ]]></content:encoded>
    </item><item>
      <title>February 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/02/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/02/01/bookmarks.html</guid>
      <pubDate>Thu, 01 Feb 2024 00:00:00 +0100</pubDate><description>Bookmarks for February 2024: 6 links - How hard is it to cheat with ChatGPT in te...; Fixing the billion dollar mistake in Go by..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://interviewing.io/blog/how-hard-is-it-to-cheat-with-chatgpt-in-technical-interviews">How hard is it to cheat with ChatGPT in technical interviews? We ran an experiment.</a></li>
  <li><a href="https://getstream.io/blog/fixing-the-billion-dollar-mistake-in-go-by-borrowing-from-rust/">Fixing the billion dollar mistake in Go by borrowing from Rust</a></li>
  <li><a href="https://zenhorace.dev/blog/context-control-go/">Context Control in Go</a></li>
  <li><a href="https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/">How I write HTTP services in Go after 13 years - Grafana Labs</a></li>
  <li><a href="https://www.geeksforgeeks.org/method-block-synchronization-java/?ref=header_search">Method and Block Synchronization in Java - GeeksforGeeks</a></li>
  <li><a href="https://www.geeksforgeeks.org/synchronization-in-java/">Synchronization in Java - GeeksforGeeks</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>Create a WC clone with Golang</title>
      <link>https://domenicoluciani.com/2024/01/29/creating-a-word-count-clone-with-golang.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/01/29/creating-a-word-count-clone-with-golang.html</guid>
      <pubDate>Mon, 29 Jan 2024 00:00:00 +0100</pubDate><description>I&apos;ve been using Golang in the past months, and I was very happy about it, this language makes me feel entertained and productive and the same time. Studying for me is a lifelong…</description>
      <content:encoded><![CDATA[
<p>I’ve been using Golang in the past months, and I was very happy about it, this language makes me feel entertained and productive and the same time. Studying for me is a lifelong journey, and with that in mind, I decided to keep using it for another challenge/project that I found quite simple but interesting. <br />
You’ll see! I spent some of my free time on it and today, I’d like to share with you which route I took to accomplish it. <br />
Let’s start!</p>

<h2 id="intro-and-coding-challenge">Intro and Coding Challenge</h2>

<p>Golang has always been one of my favorite languages and I’ve been using it for a few months so far, after my <a href="https://domenicoluciani.com/2023/11/16/buildpacks-3-months-later.html">Take 3 experience</a> I decided to keep studying it during my free time, and since I like hands-on projects, I used it to create a side-pet-challenge/project.</p>

<h2 id="coding-challenges">Coding Challenges</h2>

<p>I recently discovered <a href="https://codingchallenges.fyi/">Coding Challenges</a>, a website full of hands-on coding challenges that’s possible to take in different languages, I chose mine: Go.<br />
Sometimes I struggle to find new ideas and this website helped me a lot with that.</p>

<h2 id="wc">WC</h2>

<p>To start with something simple I decided to implement WC, the famous <a href="https://linux.die.net/man/1/wc">Word Count unix tool</a>. <br />
To learn more about it, run <code>man wc</code> in your terminal but what it essentially does is count words, lines, characters, and bytes of a specific file or pipe stream. <br />
From this very high-level point of view, it seems quite simple but digging deeper you will see that it’s not as simple as you could have thought at the beginning.</p>

<h2 id="preface">Preface</h2>

<p>Just a friendly reminder that the process I took can be avoided, improved, and of course, wrong. <br />
I’m just telling my story through this project and my Golang improving journey. <br />
Feel free to give me feedback about it and, if it makes you learn something new or reflect on a topic you never thought about,  just let me know ☀️</p>

<h3 id="first-requirement-count-bytes">First Requirement: Count bytes</h3>

<p>Starting from scratch in Go is quite simple, so I just created my repo, opened my IntelliJ Goland IDE, and, created a simple hello world ready to jump into my first requirement implementation. <br />
The first requirement is to have a small functionality, just counting the number of bytes from a specific file. <br />
Using the file that has been provided the result of this command should be:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="o">&gt;</span>./gowc <span class="nt">-c</span> test.txt
  342190 test.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s see what we got from that:</p>

<p>Input:</p>
<ul>
  <li>We have a <code>-c</code> parameter which is the way we <code>activate</code> the count bytes functionality</li>
  <li>We pass a <code>test.txt</code> which is the file we want to count from
Output:</li>
  <li>Space</li>
  <li>Number of bytes</li>
  <li>Name of the file that has been read</li>
</ul>

<p>Through my repo’s commit you can see the history of my changes, I started with something completely different (like mocking a filesystem using <code>testify/mock</code>) ending up with a bunch of simple unit tests:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">TestWcBytesReader</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads 0 bytes"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyContent</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcBytesReader</span><span class="p">()</span>  
  
       <span class="n">currentBytes</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyContent</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentBytes</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentBytes</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads 1 byte"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyContent</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span>  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcBytesReader</span><span class="p">()</span>  
  
       <span class="n">currentBytes</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyContent</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentBytes</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentBytes</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads multiple bytes"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyContent</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcBytesReader</span><span class="p">()</span>  
  
       <span class="n">currentBytes</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyContent</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">100</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentBytes</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentBytes</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
 <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The implementation as you can imagine wasn’t a big deal for this feature:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">w</span> <span class="n">WcBytesReader</span><span class="p">)</span> <span class="n">Count</span><span class="p">(</span><span class="n">content</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="kt">int64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">content</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We will skip for now how I used it in the main, if you want to try out the <em>parameter</em> part you can just use <code>flag</code> and parse that calling the Count function from there once <code>NewWcBytesReader</code> has been called.</p>

<h2 id="second-requirement-count-lines">Second Requirement: Count Lines</h2>

<p>The second requirement was to support the command line option <code>-l</code> that outputs the number of lines in a file. <br />
The CLI input/output should be:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="o">&gt;</span>./gocw <span class="nt">-l</span> test.txt
    7145 test.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s see what we got from that:</p>

<p>Input:</p>
<ul>
  <li>We have a <code>-l</code> parameter which is the way we <code>activate</code> the count bytes functionality</li>
  <li>We pass a <code>test.txt</code> which is the file we want to count from
Output:</li>
  <li>Space</li>
  <li>Number of lines</li>
  <li>Name of the file that has been read</li>
</ul>

<p>Here are some unit tests I wrote:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 0 lines with an empty file"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcLinesReader</span><span class="p">()</span>  
  
    <span class="n">currentLines</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>  
  
<span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 1 lines with just one line"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"Dummy String"</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcLinesReader</span><span class="p">()</span>  
  
    <span class="n">currentLines</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>  
  
<span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 3 lines with a multi lines file content"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"Line 1</span><span class="se">\n</span><span class="s">Line 2</span><span class="se">\n</span><span class="s">Line 3"</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcLinesReader</span><span class="p">()</span>  
  
    <span class="n">currentLines</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">3</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>  
  
<span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 3 lines with a multi lines file content with a trailing empty line"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"Line 1</span><span class="se">\n</span><span class="s">Line 2</span><span class="se">\n</span><span class="s">Line 3</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcLinesReader</span><span class="p">()</span>  
  
    <span class="n">currentLines</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">3</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">currentLines</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And here is the implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">w</span> <span class="n">WcLinesReader</span><span class="p">)</span> <span class="n">Count</span><span class="p">(</span><span class="n">content</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>  
    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>  
       <span class="k">return</span> <span class="kt">int64</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>  
    <span class="p">}</span>  
    <span class="n">lines</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">Split</span><span class="p">(</span><span class="kt">string</span><span class="p">(</span><span class="n">content</span><span class="p">),</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>  
    <span class="k">if</span> <span class="n">lines</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span> <span class="o">==</span> <span class="s">""</span> <span class="p">{</span>  
       <span class="k">return</span> <span class="kt">int64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span>  
    <span class="p">}</span>  
    <span class="k">return</span> <span class="kt">int64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">lines</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="third-requirement-count-words">Third Requirement: Count Words</h2>

<p>The third requirement was to support the command line option <code>-w</code> that outputs the number of words in a file. <br />
The CLI input/output should be:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="o">&gt;</span>./gocw <span class="nt">-w</span> test.txt
   58164 test.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s see what we got from that:</p>

<p>Input:</p>
<ul>
  <li>We have a <code>-w</code> parameter which is the way we <code>activate</code> the count words functionality</li>
  <li>We pass a <code>test.txt</code> which is the file we want to count from
Output:</li>
  <li>Space</li>
  <li>Number of words</li>
  <li>Name of the file that has been read</li>
</ul>

<p>The unit tests I wrote:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 0 if the file doesn't have words"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcWordsReader</span><span class="p">()</span>  
  
    <span class="n">nWords</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nWords</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nWords</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>  
  
<span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 1 if the file have just 1 word"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"Dummy"</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcWordsReader</span><span class="p">()</span>  
  
    <span class="n">nWords</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nWords</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nWords</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>  
  
<span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count returns 3 if the file have 3 words"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"Dummy Word Here"</span><span class="p">)</span>  
    <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcWordsReader</span><span class="p">()</span>  
    <span class="n">nWords</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
    <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">3</span><span class="p">)</span>  
    <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nWords</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nWords</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see I maintained always the same <em>style</em>, starting with a simpler scenario, and moving up to a more complex one.</p>

<p>The implementation:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">w</span> <span class="n">WcWordsReader</span><span class="p">)</span> <span class="n">Count</span><span class="p">(</span><span class="n">content</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>  
    <span class="n">words</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">Fields</span><span class="p">(</span><span class="kt">string</span><span class="p">(</span><span class="n">content</span><span class="p">))</span>  
  
    <span class="k">return</span> <span class="kt">int64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">words</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here instead of spending lots of time understanding what type of words I want to support, how Golang interprets and counts them, considering corner cases, Unicode characters, etc. I decided to use the <code>strings.Fields</code> method, according to the doc:</p>

<blockquote>
  <p>Fields splits the string s around each instance of one or more consecutive white space characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an empty slice if s contains only white space.
– <cite>Golang Doc</cite></p>
</blockquote>

<p>My goal wasn’t to reinvent the wheel, and in some contexts/domains (i.e. security) you shouldn’t too.</p>

<h2 id="fourth-requirement-count-characters">Fourth Requirement: Count Characters</h2>

<p>The fourth requirement was to support the command line option <code>-m</code> that outputs the number of characters in a file. <br />
The CLI input/output should be:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="o">&gt;</span>./gocw <span class="nt">-m</span> test.txt
  339292 test.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s see what we got from that:</p>

<p>Input:</p>
<ul>
  <li>We have a <code>-m</code> parameter which is the way we <code>activate</code> the count chars functionality</li>
  <li>We pass a <code>test.txt</code> which is the file we want to count from
Output:</li>
  <li>Space</li>
  <li>Number of chars</li>
  <li>Name of the file that has been read</li>
</ul>

<p>The unit tests I wrote:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">TestWcCharsReader</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads 0 chars"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>  
  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcCharsReader</span><span class="p">()</span>  
       <span class="n">nChars</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
    
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads 1 char"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"a"</span><span class="p">)</span>  
  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcCharsReader</span><span class="p">()</span>  
       <span class="n">nChars</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads multiple chars"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"abc"</span><span class="p">)</span>  
  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcCharsReader</span><span class="p">()</span>  
       <span class="n">nChars</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">3</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Count reads multiple chars included unicode ones"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">dummyFile</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"🚀"</span><span class="p">)</span>  
  
       <span class="n">r</span> <span class="o">:=</span> <span class="n">NewWcCharsReader</span><span class="p">()</span>  
       <span class="n">nChars</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">dummyFile</span><span class="p">)</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="kt">int64</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="s">"Got %d, wanted %d"</span><span class="p">,</span> <span class="n">nChars</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>  
    <span class="p">})</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I still used the same format as before, the last test is different since it allows us to test Unicode characters (in this case an emoji). As you might know, Unicode characters are counted differently, if you want to know more about it, read this article: <a href="https://tonsky.me/blog/unicode/">https://tonsky.me/blog/unicode/</a></p>

<p>And the following implementation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="p">(</span><span class="n">w</span> <span class="n">WcCharsReader</span><span class="p">)</span> <span class="n">Count</span><span class="p">(</span><span class="n">content</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="kt">int64</span><span class="p">(</span><span class="n">utf8</span><span class="o">.</span><span class="n">RuneCount</span><span class="p">(</span><span class="n">content</span><span class="p">))</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The <code>utf8.RuneCount</code> method allows me to count the number of runes in a string considering utf-8s also.</p>

<blockquote>
  <p>RuneCount returns the number of runes in p. Erroneous and short encodings are treated as single runes of width 1 byte.
– <cite>Golang Doc</cite></p>
</blockquote>

<h2 id="fifth-requirement-default-options">Fifth Requirement: Default options</h2>

<p>In this step, we should support the default option which means: no options have been provided which will be translated as we activate the <code>-c</code>, <code>-l</code>, and <code>-w</code> options. <br />
The CLI input/output should be then:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="o">&gt;</span>./gocw test.txt
    7145   58164  342190 test.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Since we have already implemented all functionalities we just need to rearrange the way we activate them. <br />
At first look, it seems that having something like:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="o">*</span><span class="n">flagBytes</span> <span class="o">==</span> <span class="no">true</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="o">*</span><span class="n">flagLines</span> <span class="o">==</span> <span class="no">true</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="o">*</span><span class="n">flagWords</span> <span class="o">==</span> <span class="no">true</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="k">else</span> <span class="p">{</span> <span class="n">activeDefaultOptions</span><span class="p">()</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Might work fine but I wanted to improve it a bit, I didn’t like the idea that if I wanted to add new functionality I needed to touch/duplicate lots of code. <br />
In the beginning, I got confused and I thought that each option needed to have a filename attached having something like this <code>-c filename.txt -w filename.txt</code>, but then I realized that my solution would lead to a very complex solution since <code>flag</code> doesn’t support “empty” flags, if not passing some default values which in case of strings would have been difficult. <br />
So I reverted my design choice to a simpler one, using boolean flags instead.</p>

<h3 id="parameters">Parameters</h3>

<p>I don’t like having everything in the main, so I created a <code>parameters</code> dir and wrote some unit tests:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">TestParameters</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Parameters have been provided"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">os</span><span class="o">.</span><span class="n">Args</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"wc"</span><span class="p">,</span> <span class="s">"-l"</span><span class="p">,</span> <span class="s">"text.txt"</span><span class="p">}</span>  
  
       <span class="n">actual</span> <span class="o">:=</span> <span class="n">HasProvided</span><span class="p">()</span>  
  
       <span class="n">assert</span><span class="o">.</span><span class="n">Truef</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">actual</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="no">true</span><span class="p">,</span> <span class="n">actual</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Parameters haven't been provided"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">os</span><span class="o">.</span><span class="n">Args</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"wc"</span><span class="p">}</span>  
  
       <span class="n">actual</span> <span class="o">:=</span> <span class="n">HasProvided</span><span class="p">()</span>  
  
       <span class="n">assert</span><span class="o">.</span><span class="n">Falsef</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">actual</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="no">false</span><span class="p">,</span> <span class="n">actual</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Get filename from parameter provided"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">os</span><span class="o">.</span><span class="n">Args</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"wc"</span><span class="p">,</span> <span class="s">"-l"</span><span class="p">,</span> <span class="s">"text.txt"</span><span class="p">}</span>  
  
       <span class="n">actual</span> <span class="o">:=</span> <span class="n">GetFilename</span><span class="p">()</span>  
  
       <span class="n">expected</span> <span class="o">:=</span> <span class="s">"text.txt"</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">actual</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="n">expected</span><span class="p">,</span> <span class="n">actual</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Get true if at least one flag has been passed"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">getBooleanPointer</span> <span class="o">:=</span> <span class="k">func</span><span class="p">(</span><span class="n">b</span> <span class="kt">bool</span><span class="p">)</span> <span class="o">*</span><span class="kt">bool</span> <span class="p">{</span> <span class="k">return</span> <span class="o">&amp;</span><span class="n">b</span> <span class="p">}</span>  
       <span class="n">flags</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="kt">bool</span><span class="p">{</span>  
          <span class="s">"c"</span><span class="o">:</span> <span class="n">getBooleanPointer</span><span class="p">(</span><span class="no">false</span><span class="p">),</span>  
          <span class="s">"d"</span><span class="o">:</span> <span class="n">getBooleanPointer</span><span class="p">(</span><span class="no">true</span><span class="p">),</span>  
          <span class="s">"e"</span><span class="o">:</span> <span class="n">getBooleanPointer</span><span class="p">(</span><span class="no">false</span><span class="p">),</span>  
       <span class="p">}</span>  
       <span class="n">actualName</span><span class="p">,</span> <span class="n">actualBool</span> <span class="o">:=</span> <span class="n">HaveBeenPassed</span><span class="p">(</span><span class="n">flags</span><span class="p">)</span>  
  
       <span class="n">expectedName</span> <span class="o">:=</span> <span class="s">"d"</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expectedName</span><span class="p">,</span> <span class="n">actualName</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="n">expectedName</span><span class="p">,</span> <span class="n">actualName</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Truef</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">actualBool</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="no">true</span><span class="p">,</span> <span class="n">actualBool</span><span class="p">)</span>  
    <span class="p">})</span>
      
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"Get false if no flags have been passed"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">getBooleanPointer</span> <span class="o">:=</span> <span class="k">func</span><span class="p">(</span><span class="n">b</span> <span class="kt">bool</span><span class="p">)</span> <span class="o">*</span><span class="kt">bool</span> <span class="p">{</span> <span class="k">return</span> <span class="o">&amp;</span><span class="n">b</span> <span class="p">}</span>  
       <span class="n">flags</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="kt">bool</span><span class="p">{</span>  
          <span class="s">"c"</span><span class="o">:</span> <span class="n">getBooleanPointer</span><span class="p">(</span><span class="no">false</span><span class="p">),</span>  
          <span class="s">"d"</span><span class="o">:</span> <span class="n">getBooleanPointer</span><span class="p">(</span><span class="no">false</span><span class="p">),</span>  
          <span class="s">"e"</span><span class="o">:</span> <span class="n">getBooleanPointer</span><span class="p">(</span><span class="no">false</span><span class="p">),</span>  
       <span class="p">}</span>  
       <span class="n">actualName</span><span class="p">,</span> <span class="n">actualBool</span> <span class="o">:=</span> <span class="n">HaveBeenPassed</span><span class="p">(</span><span class="n">flags</span><span class="p">)</span>  
  
       <span class="n">expectedName</span> <span class="o">:=</span> <span class="s">""</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">expectedName</span><span class="p">,</span> <span class="n">actualName</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="n">expectedName</span><span class="p">,</span> <span class="n">actualName</span><span class="p">)</span>  
       <span class="n">assert</span><span class="o">.</span><span class="n">Falsef</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">actualBool</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="no">true</span><span class="p">,</span> <span class="n">actualBool</span><span class="p">)</span>  
    <span class="p">})</span>
 <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="check-if-weve-got-parameters">Check if we’ve got parameters</h3>
<p>The functions I implemented are:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">HasProvided</span><span class="p">()</span> <span class="kt">bool</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">1</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>It gives to me if parameters have been provided.</p>

<h3 id="get-the-filename-from-the-command-line">Get the filename from the command line</h3>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">GetFilename</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">Args</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Args</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>It gives me the last parameter entry which should be the filename.</p>

<h3 id="check-if-a-specific-flag-has-been-passed">Check if a specific flag has been passed</h3>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">HaveBeenPassed</span><span class="p">(</span><span class="n">flags</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="kt">bool</span><span class="p">)</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>  
    <span class="k">for</span> <span class="n">flagName</span><span class="p">,</span> <span class="n">flagValue</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">flags</span> <span class="p">{</span>  
       <span class="k">if</span> <span class="o">*</span><span class="n">flagValue</span> <span class="o">==</span> <span class="no">true</span> <span class="p">{</span>  
          <span class="k">return</span> <span class="n">flagName</span><span class="p">,</span> <span class="no">true</span>  
       <span class="p">}</span>  
    <span class="p">}</span>    <span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="no">false</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>It gives me the first flag that has been activated.</p>

<h3 id="flag-initialization-and-parsing">Flag initialization and parsing</h3>
<p>To initialize and get the flags I also wrote a function:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">GetFlags</span><span class="p">()</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="kt">bool</span> <span class="p">{</span>  
    <span class="n">flags</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="kt">bool</span><span class="p">{</span>  
       <span class="n">BytesFlag</span><span class="o">:</span> <span class="n">flag</span><span class="o">.</span><span class="n">Bool</span><span class="p">(</span><span class="n">BytesFlag</span><span class="p">,</span> <span class="no">false</span><span class="p">,</span> <span class="s">"Count bytes of the file"</span><span class="p">),</span>  
       <span class="n">LinesFlag</span><span class="o">:</span> <span class="n">flag</span><span class="o">.</span><span class="n">Bool</span><span class="p">(</span><span class="n">LinesFlag</span><span class="p">,</span> <span class="no">false</span><span class="p">,</span> <span class="s">"Count lines of the file"</span><span class="p">),</span>  
       <span class="n">WordsFlag</span><span class="o">:</span> <span class="n">flag</span><span class="o">.</span><span class="n">Bool</span><span class="p">(</span><span class="n">WordsFlag</span><span class="p">,</span> <span class="no">false</span><span class="p">,</span> <span class="s">"Count words of the file"</span><span class="p">),</span>  
       <span class="n">CharsFlag</span><span class="o">:</span> <span class="n">flag</span><span class="o">.</span><span class="n">Bool</span><span class="p">(</span><span class="n">CharsFlag</span><span class="p">,</span> <span class="no">false</span><span class="p">,</span> <span class="s">"Count chars of the file"</span><span class="p">),</span>  
    <span class="p">}</span>  
    <span class="n">flag</span><span class="o">.</span><span class="n">Parse</span><span class="p">()</span>  
  
    <span class="k">return</span> <span class="n">flags</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>It creates a map with strings as key (specific const variables), and a bool which is the boolean value that <code>flag</code> sets following the CLI parameters.</p>

<h3 id="const-variables">Const variables</h3>
<p>It refers to the const variables, which are the keys of the <code>GetFlags</code> map and our parameters:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">const</span> <span class="p">(</span>  
    <span class="n">BytesFlag</span> <span class="o">=</span> <span class="s">"c"</span>  
    <span class="n">LinesFlag</span> <span class="o">=</span> <span class="s">"l"</span>  
    <span class="n">WordsFlag</span> <span class="o">=</span> <span class="s">"w"</span>  
    <span class="n">CharsFlag</span> <span class="o">=</span> <span class="s">"m"</span>  
<span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So if tomorrow we need to add a new parameter we can just add a new Constant, add it to our map with the respective <code>flag.Bool</code> call, and everything is encapsulated inside the <code>parameters.go</code> file.</p>

<p>So going back to our main we have to get the input combining the functions above:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">getInput</span><span class="p">()</span> <span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">parameters</span><span class="o">.</span><span class="n">HasProvided</span><span class="p">()</span> <span class="p">{</span>  
		 <span class="n">filename</span> <span class="o">:=</span> <span class="n">parameters</span><span class="o">.</span><span class="n">GetFilename</span><span class="p">()</span>  
		 <span class="k">return</span> <span class="n">readFile</span><span class="p">(</span><span class="n">filename</span><span class="p">),</span> <span class="n">filename</span>  
	<span class="p">}</span>
    <span class="k">return</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="n">EmptyString</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I created a private function to verify if some parameters have been passed, and then I got the file name and read it, returning the content.</p>

<p>Then after setting and getting the flags using the function <code>parameters.GetFlags()</code> I initialized my readers using the function <code>reader.InitializeReaders()</code> which instantiates all readers storing them into a map of <code>strings-WcReaderManager</code>:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">InitializeReaders</span><span class="p">()</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">WcReaderManager</span> <span class="p">{</span>  
    <span class="k">return</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">WcReaderManager</span><span class="p">{</span>  
       <span class="n">parameters</span><span class="o">.</span><span class="n">BytesFlag</span><span class="o">:</span> <span class="n">bytesReader</span><span class="o">.</span><span class="n">NewWcBytesReader</span><span class="p">(),</span>  
       <span class="n">parameters</span><span class="o">.</span><span class="n">LinesFlag</span><span class="o">:</span> <span class="n">linesReader</span><span class="o">.</span><span class="n">NewWcLinesReader</span><span class="p">(),</span>  
       <span class="n">parameters</span><span class="o">.</span><span class="n">WordsFlag</span><span class="o">:</span> <span class="n">wordsReader</span><span class="o">.</span><span class="n">NewWcWordsReader</span><span class="p">(),</span>  
       <span class="n">parameters</span><span class="o">.</span><span class="n">CharsFlag</span><span class="o">:</span> <span class="n">charsReader</span><span class="o">.</span><span class="n">NewWcCharsReader</span><span class="p">(),</span>  
    <span class="p">}</span>
 <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once initialized I verify, calling the function <code>parameters.HaveBeenPassed(flags)</code> if any parameter has been passed.</p>

<ul>
  <li>If so, I call <code>reader.CountWithSpecificReader(initializedReaders[flagNamePassed], input)</code> which the implementation is:
    <div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">CountWithSpecificReader</span><span class="p">(</span><span class="n">specificReader</span> <span class="n">WcReaderManager</span><span class="p">,</span> <span class="n">input</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>  
  <span class="k">return</span> <span class="n">specificReader</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
</ul>

<p>It gets a specificReader due to the flag that has been passed and the input which is the content of the file. <br />
It calls the function <code>Count</code> returning the output.</p>

<ul>
  <li>Otherwise we call the function <code>reader.CountBytesWordsAndLines(initializedReaders, input)</code> which uses the initialized readers that have been saved into the map to count the input for the 3 default options: bytes, words, and lines. The implementation is:
    <div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">CountBytesWordsAndLines</span><span class="p">(</span><span class="n">readers</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">WcReaderManager</span><span class="p">,</span> <span class="n">input</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="kt">int64</span><span class="p">,</span> <span class="kt">int64</span><span class="p">)</span> <span class="p">{</span>  
  <span class="k">return</span> <span class="n">readers</span><span class="p">[</span><span class="n">parameters</span><span class="o">.</span><span class="n">BytesFlag</span><span class="p">]</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">input</span><span class="p">),</span>  
     <span class="n">readers</span><span class="p">[</span><span class="n">parameters</span><span class="o">.</span><span class="n">WordsFlag</span><span class="p">]</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">input</span><span class="p">),</span>  
     <span class="n">readers</span><span class="p">[</span><span class="n">parameters</span><span class="o">.</span><span class="n">LinesFlag</span><span class="p">]</span><span class="o">.</span><span class="n">Count</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
</ul>

<p>I was able to accomplish that thanks to the <code>WcReaderManager</code> interface:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">WcReaderManager</span> <span class="k">interface</span> <span class="p">{</span>  
    <span class="n">Count</span><span class="p">(</span><span class="n">content</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">int64</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you are curious about the approach I used, have a look into the <a href="https://refactoring.guru/design-patterns/strategy">Strategy Pattern</a>.</p>

<h2 id="final-step">Final step</h2>

<p>The final step is about supporting reading from standard input if no filename is specified.</p>

<p>The CLI input/output should be:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="o">&gt;</span><span class="nb">cat </span>test.txt | ./gocw <span class="nt">-l</span>
    7145
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To do that I created a directory called <code>pipeline</code>, containing useful functions to solve the problem, here are the unit tests I wrote:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">TestPipeline</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"HasInput should return false if an input hasn't come from pipeline"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">actual</span> <span class="o">:=</span> <span class="n">HasInput</span><span class="p">()</span>  
  
       <span class="n">assert</span><span class="o">.</span><span class="n">Falsef</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">actual</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="no">true</span><span class="p">,</span> <span class="n">actual</span><span class="p">)</span>  
    <span class="p">})</span>    
    
    <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="s">"HasInput should truw if an input comes from pipeline"</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>  
       <span class="n">r</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">Pipe</span><span class="p">()</span>  
       <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">w</span><span class="o">.</span><span class="n">Write</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="s">"Hello"</span><span class="p">))</span>  
       <span class="n">_</span> <span class="o">=</span> <span class="n">w</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>  
       <span class="n">os</span><span class="o">.</span><span class="n">Stdin</span> <span class="o">=</span> <span class="n">r</span>  
       <span class="k">defer</span> <span class="k">func</span><span class="p">(</span><span class="n">v</span> <span class="o">*</span><span class="n">os</span><span class="o">.</span><span class="n">File</span><span class="p">)</span> <span class="p">{</span> <span class="n">os</span><span class="o">.</span><span class="n">Stdin</span> <span class="o">=</span> <span class="n">v</span> <span class="p">}(</span><span class="n">os</span><span class="o">.</span><span class="n">Stdin</span><span class="p">)</span>  
  
       <span class="n">actual</span> <span class="o">:=</span> <span class="n">HasInput</span><span class="p">()</span>  
  
       <span class="n">assert</span><span class="o">.</span><span class="n">Truef</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">actual</span><span class="p">,</span> <span class="s">"expected %t, got %t"</span><span class="p">,</span> <span class="no">true</span><span class="p">,</span> <span class="n">actual</span><span class="p">)</span>  
    <span class="p">})</span>
 <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And here is the implementation:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">HasInput</span><span class="p">()</span> <span class="kt">bool</span> <span class="p">{</span>  
    <span class="n">f</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">Stdin</span><span class="o">.</span><span class="n">Stat</span><span class="p">()</span>  
    <span class="k">return</span> <span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">Mode</span><span class="p">()</span> <span class="o">&amp;</span> <span class="n">os</span><span class="o">.</span><span class="n">ModeCharDevice</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">ReadInput</span><span class="p">()</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>  
    <span class="n">input</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">io</span><span class="o">.</span><span class="n">ReadAll</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Stdin</span><span class="p">)</span>  
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>  
       <span class="n">log</span><span class="o">.</span><span class="n">Fatalf</span><span class="p">(</span><span class="s">"Error reading the pipeline: %v"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>  
    <span class="p">}</span>    <span class="k">return</span> <span class="n">input</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I check if the information that we get from the standard input is coming from a pipe operator, and then I just updated the <code>getInput</code> function used before:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">getInput</span><span class="p">()</span> <span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>  
    <span class="k">const</span> <span class="n">EmptyString</span> <span class="o">=</span> <span class="s">""</span>  
  
    <span class="k">if</span> <span class="n">pipeline</span><span class="o">.</span><span class="n">HasInput</span><span class="p">()</span> <span class="p">{</span>  
       <span class="k">return</span> <span class="n">pipeline</span><span class="o">.</span><span class="n">ReadInput</span><span class="p">(),</span> <span class="n">EmptyString</span>  
    <span class="p">}</span>  
  
    <span class="k">if</span> <span class="n">parameters</span><span class="o">.</span><span class="n">HasProvided</span><span class="p">()</span> <span class="p">{</span>  
       <span class="n">filename</span> <span class="o">:=</span> <span class="n">parameters</span><span class="o">.</span><span class="n">GetFilename</span><span class="p">()</span>  
       <span class="k">return</span> <span class="n">readFile</span><span class="p">(</span><span class="n">filename</span><span class="p">),</span> <span class="n">filename</span>  
    <span class="p">}</span>  
  
    <span class="k">return</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="n">EmptyString</span>  
<span class="p">}</span>  
  
<span class="k">func</span> <span class="n">readFile</span><span class="p">(</span><span class="n">filename</span> <span class="kt">string</span><span class="p">)</span> <span class="p">[]</span><span class="kt">byte</span> <span class="p">{</span>  
    <span class="n">input</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">ReadFile</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>  
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>  
       <span class="n">log</span><span class="o">.</span><span class="n">Fatalf</span><span class="p">(</span><span class="s">"Error reading the file: %v"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>  
    <span class="p">}</span>    <span class="k">return</span> <span class="n">input</span>  
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="directory-structure">Directory Structure</h2>

<pre><code class="language-txt">- gowc
	- parameters
	- pipeline
	- reader
		- bytes
		- chars
		- lines
		- words
	- testdata
</code></pre>

<ol>
  <li>In the <code>parameters</code> directory I’ve put everything related to parameters, which means the definition of the parameters and some helpers.</li>
  <li>In the <code>pipeline</code> directory I’ve put everything about the way to pass information through the pipe operator and the standard input, like identifying when it happens and how to read from it</li>
  <li>In the <code>reader</code> directory I have everything related to my readers, the main reader file contains the interface <code>WcReaderManager</code> which has a <code>Count</code> function, and some helpers to initialize the readers.</li>
  <li>The <code>testdata</code> directory was just a place where to store the sample file.</li>
</ol>

<p>It required a bit of refactoring to get into this shape, inside the <code>reader</code> directory there is the core of my application beginning with the <code>reader.go</code> file, it contains the <code>WcReaderManager</code> interface and a bunch of function which help me to initialize and call in specific ways my readers. <br />
Under each <code>bytes</code>, <code>chars</code>, <code>lines</code>, and <code>words</code> directory there is the actual implementation that will be executed when needed.</p>

<p>As you can see it helps me to isolate and make it clear what each function belongs to. Having calls like <code>parameters.HasProvided()</code>, <code>pipeline.HasInput()</code>, <code>reader.CountWithSpecificReader(...)</code> really improve the reading and the understanding, I like this structure for this reason.</p>

<h2 id="final-thoughts">Final Thoughts</h2>

<p>Of course the development process wasn’t this smooth, there were trials and errors here and there, as it’s supposed to be.</p>

<blockquote>
  <p>Perfect is the enemy of good enough</p>
</blockquote>

<p>I tried to face this coding challenge by reading one requirement after the other and doing a step-by-step evolution in my codebase. <br />
It means that I’ve had to change and adapt my code to the new requirements. <br />
Yeah, I faced this challenge like that it was a real scenario and this is the way I think is the best way to learn: on the job.</p>

<p>In the beginning, it seemed quite simple, I just needed to do some counting here and there, but then at every green test, I felt the urge to clean and refactor my codebase.</p>

<blockquote>
  <p>Friendly reminder, refactoring should be part of your definition of done.</p>
</blockquote>

<p>With each iteration, my codebase evolved into something more clear and thanks to my testing strategy I could do it in no time. <br />
Sure, I had to move from different design decisions to others but that’s normal in a codebase, consider that whenever you touch some code. Sooner or later you will need to change that and how coupled it is to other components that will make the difference in the long run.</p>

<p>If you want to have a look at the code, you can find it on my Github Profile: <a href="https://github.com/dlion/gowc">https://github.com/dlion/gowc</a>.</p>

<p>So what do you think about my solution? <br />
Did I miss something? Can I improve it? Can it be more idiomatic?</p>

<p>Of course this solution can be definitely improved, and the exercise wasn’t about reading large files (given the example file). <br />
In that case I would have implemented the reader in a different way in order to not have the entire file in memory and so on.</p>

<p>Implement your solution and let me know what you think about this challenge.</p>

<p>Happy Coding!</p>

      ]]></content:encoded>
    </item><item>
      <title>PointerPodcast - Buildpacks and Extreme Programming</title>
      <link>https://domenicoluciani.com/2024/01/12/pointerpodcast-extreme-programming-buildpacks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/01/12/pointerpodcast-extreme-programming-buildpacks.html</guid>
      <pubDate>Fri, 12 Jan 2024 00:00:00 +0100</pubDate><description>I decided to expose myself more and more, I like to share my opinions and experiences (you can say reading this blog), and this time I decided to attend as a interviewee for a well known Podcast in Italy talking about something I&apos;ve done for 3 months, are you curious about it?</description>
      <content:encoded><![CDATA[
<p>I decided to expose myself more and more, I like to share my opinions and experiences (you can say reading this blog), and this time I decided to attend as a interviewee for a well known Podcast in Italy talking about something I’ve done for 3 months, are you curious about it?</p>

<p>A few weeks ago, I’ve been interviewed by <a href="https://pointerpodcast.it/">PointerPodcast</a> about my experience during my <a href="https://domenicoluciani.com/2023/11/16/buildpacks-3-months-later.html">Take 3</a> and how I work in Tanzu Labs.</p>

<p>It was quite fan, even tho in some points I feel there will be more and more to talk about, I just barely scratched the surface. <br />
Yeah sorry for any english speaker, it’s in Italian 🇮🇹</p>

<p>You can find the episode on Spotify and Apple Podcast here:</p>

<p><a href="https://pointerpodcast.it/p/pointer185-extreme-programming-e-buildpacks-con-domenico-luciani-tanzu-labs/"><img src="/assets/images/posts/pointerpodcast.png" alt="pointerpodcast" /></a></p>


      ]]></content:encoded>
    </item><item>
      <title>January 2024 - Bookmarks</title>
      <link>https://domenicoluciani.com/2024/01/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2024/01/01/bookmarks.html</guid>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0100</pubDate><description>Bookmarks for January 2024: 5 links - Perfectionism and Procrastination: How The...; Advice to Young People, The Lies I Tell My..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://solvingprocrastination.com/perfectionism/">Perfectionism and Procrastination: How They’re Connected and What to Do About It – Solving Procrastination</a></li>
  <li><a href="https://jxnl.github.io/blog/writing/2024/06/01/advice-to-young-people/#you-are-a-mirror">Advice to Young People, The Lies I Tell Myself - jxnl.co</a></li>
  <li><a href="https://hbr.org/2023/12/research-the-growing-inequality-of-who-gets-to-work-from-home">Research: The Growing Inequality of Who Gets to Work from Home</a></li>
  <li><a href="https://notes.billmill.org/computer_usage/zsh/profiling_zsh_startup.html">profiling zsh startup - llimllib notes</a></li>
  <li><a href="https://nvie.com/posts/a-successful-git-branching-model/">A successful Git branching model » nvie.com</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>December 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/12/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/12/01/bookmarks.html</guid>
      <pubDate>Fri, 01 Dec 2023 00:00:00 +0100</pubDate><description>Bookmarks for December 2023: 1 link - BeckDesignRules.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://martinfowler.com/bliki/BeckDesignRules.html">BeckDesignRules</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>Buildpacks - 3 months later</title>
      <link>https://domenicoluciani.com/2023/11/16/buildpacks-3-months-later.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/11/16/buildpacks-3-months-later.html</guid>
      <pubDate>Thu, 16 Nov 2023 00:00:00 +0100</pubDate><description>Since the beginning of my career in this industry, I&apos;ve always been fascinated by the open-source world. After so many years of contributing on my own, this year, I finally joined…</description>
      <content:encoded><![CDATA[
<p>Since the beginning of my career in this industry, I’ve always been fascinated by the open-source world. <br />
After so many years of contributing on my own, this year, I finally joined for 3 months an open-source team within VMware and discovered how an open-source team works. <br />
In this article, I’m going to tell you more about this open-source journey and how it went. Let’s go! 🚀</p>

<h2 id="take-3">Take 3</h2>

<p>I’d like to start with how I ended up working full-time on an open-source project, and to do so, I have to describe what a VMware Take3 initiative is.</p>

<p><a href="https://www.vmware.com/">VMware</a>, the company I currently work for, gives everyone the fantastic opportunity to join another team within the company for a limited amount of time, usually 3 months (that’s why the 3 😉).</p>

<p>Every team that needs some help or that is open to accepting temporary new joiners can publish an opportunity in an internal platform. Sometimes they require specific skills, proficiency in a particular stack, or just people with the motivation to learn new things.</p>

<p>Everyone who has the approval can apply to those opportunities, and have a conversation with the manager who published it to verify whether that person might be a good fit or not. <br />
As you can imagine I went through this process early this July and, I applied for a Take3 to join a small open-source team called <strong>CNB</strong> - <strong>Cloud Native Buildpacks</strong>.</p>

<h2 id="what-do-buildpacks-do">What do Buildpacks do?</h2>

<p><strong>TLDR</strong>: Buildpacks turn your code into OCI-compliant containers. They examine your source code, build it, and create a container image with all the required dependencies to run your application. ⚡️</p>

<p>Using Dockerfiles can be exhausting, you have to make lots of decisions like which base image you want to use and which version, being sure that all your application dependencies are ok with it. After that, you need to bring additional dependencies, and runtimes, build your application, and finally optimize all these operations to have an optimized container. <br />
Cloud Native Buildpacks on the other hand would take care of all these steps, at least for most of the common use cases. <br />
Your container also needs to be maintained over time, using your Dockerfiles you don’t have a real separation between the base image, the runtime, your dependencies, and your application so updating the image would require rebuilding it every time.</p>

<p>Cloud Native Buildpacks create different layers that can be swapped with new versions like Legos. 🧱 <br />
If you want to know more about it, have a look at the <a href="https://buildpacks.io/">Cloud Native Buildpacks website</a>.</p>

<h2 id="cloud-native-buildpacks---the-team">Cloud Native Buildpacks - The team</h2>

<p>CNB stands for <a href="https://buildpacks.io/">Cloud Native Buildpacks</a>, it’s a small team composed of amazing people who are spending their daily time on repositories like <a href="https://github.com/buildpacks/pack">Buildpacks/Pack</a> and <a href="https://github.com/buildpacks/lifecycle">Buildpacks/Lifecycle</a>. <br />
Their main duty is to help the Buildpacks maintainers and the Buildpacks community, they take care of the issues, develop new features, attend numerous working group meetings, and help release new versions.</p>

<h2 id="how-does-the-cloud-native-buildpacks-open-source-team-work">How does the Cloud Native Buildpacks Open Source team work?</h2>

<p>The Open Source world is <em>HUGE</em>, and a standard to follow doesn’t exist yet, so every experience can be unique. 👈🏻 <br />
The team’s favorite way of working is to be <a href="https://handbook.gitlab.com/handbook/company/culture/all-remote/asynchronous/">async</a> as much as possible due to the different timezones involved and then take advantage of the overlapped hours to pair/sync if necessary. <br />
We were using an async standup where we could raise blockers and/or keep the rest of the team up-to-date.</p>

<p>During the week we had different meetings:</p>
<ul>
  <li>Internal Sync with other teams
    <ul>
      <li>In the internal sync meetings a representative of the team kept other teams informed about the work in progress and possible new initiatives and events.</li>
    </ul>
  </li>
  <li>Working Groups
    <ul>
      <li>During these meetings, we catch up with maintainers, other collaborators, and people with specific requests and problems. This meeting was one of the most interesting ones for me, it gave me the occasion to meet people working for other companies, from Google to Bloomberg.</li>
    </ul>
  </li>
  <li>Iteration Planning Meetings
    <ul>
      <li>During these meetings, each of us talked about the tasks in progress, and their status, and asked for help and possible future initiatives.</li>
    </ul>
  </li>
  <li>Knowledge sharing meetings
    <ul>
      <li>These meetings were about sharing interesting stuff, they could be very effective during the onboarding process or just to dive deeper into some fun topics.</li>
    </ul>
  </li>
  <li>Social meetings
    <ul>
      <li>Working remotely doesn’t mean you have to be alone the whole time, these meetings were a nice opportunity to know each other better, talk about anything, and play some nice games. It was very refreshing knowing that behind such talented people, there were extraordinary human beings.</li>
    </ul>
  </li>
  <li>Pairing Sessions
    <ul>
      <li>Pairing was crucial to get onboarded and help faster. Collaborating so closely with other team members helped me to get confident with the codebase and to answer many questions that I -could- definitely have</li>
    </ul>
  </li>
</ul>

<h3 id="how-a-day-within-the-team-looked-like">How a day within the team looked like</h3>

<p>Most of my mornings were free from meetings due to the different time zones, so I could focus on getting things done. 🚀 <br />
Getting things done meant continuing my tasks in progress, reviewing issues opened, and reviewing PRs. Being in a different timezone allowed me to interact efficiently with whom was in my timezone as well. <br />
In the afternoon it’s when I had most of my meetings, I could catch up with the rest of the team and join the necessary meetings explained above, besides, of course, our pairing sessions.</p>

<h2 id="expectations">Expectations</h2>
<p>The expectations that have been set for me was to be able to deliver <em>one</em> feature at the end of the 3 months of the Take3.</p>

<p>My todo list was kind of similar:</p>
<ul>
  <li>First week: get onboarded
    <ul>
      <li>Learn about the project, the team, the codebase, etc.</li>
    </ul>
  </li>
  <li>Second week: try to work on a first good issue
    <ul>
      <li>Usually, they are very simple issues</li>
    </ul>
  </li>
  <li>3 Months: Deliver a feature
    <ul>
      <li>E2E Ownership</li>
    </ul>
  </li>
</ul>

<h2 id="golang">Golang</h2>
<p>Despite my long experience jumping from one stack to another, I’ve had just one occasion to push any written Golang code to prod so far, and it was a few years ago. Now, the challenge was to re-learn it and, to kind of push it to prod. <br />
Kind of because our “prod” was a “release” state, not a real prod env, since the software I was working on was mainly a CLI app. <br />
Honestly, I liked Golang and I was able to use it quite effectively in no time. I liked to work with this language and I would like to work again with it in the future. 👀</p>

<h2 id="first-feature">First Feature</h2>
<p>Thanks to my years of experience jumping from one stack to another as a consultant Extreme Programmer, I could re-learn the basics of the Go language quite quickly and, I’ve got my first feature merged <em>within one week</em>.</p>

<p>I picked up one first good issue: <a href="https://github.com/buildpacks/pack/issues/1800">https://github.com/buildpacks/pack/issues/1800</a> and created a PR that has been merged within 1 week: <a href="https://github.com/buildpacks/pack/pull/1810">https://github.com/buildpacks/pack/pull/1810</a>. 🥳 <br />
At that moment, I was officially a <em>paid Open Source contributor</em>. 🚀</p>

<h2 id="open-source-contributor">Open Source Contributor</h2>

<p>I started contributing to the Open Source when I was young, I think I was 17 years old, this is my first contribution ever: <a href="https://github.com/toshidex/DefollowNotify/pull/1">https://github.com/toshidex/DefollowNotify/pull/1</a>. <br />
Then I ‘ve been an Hacktoberfest contributor: <a href="https://domenicoluciani.com/2018/01/10/hacktoberfest-swag.html">2017</a>, <a href="https://domenicoluciani.com/2019/02/10/hacktoberfest-18.html">2018</a>, <a href="https://domenicoluciani.com/2019/12/18/hacktoberfest-19.html">2019</a>, <a href="https://domenicoluciani.com/2021/01/31/hacktoberfest2020.html">2020</a>. <br />
And finally, after so many years, I was a paid open-source contributor. I was so happy that I had to <a href="https://www.linkedin.com/posts/dlion_github-buildpackspack-cli-for-building-activity-7079918050530975744-btba">share it on Linkedin too</a>.</p>

<h3 id="back-to-labs">Back to Labs</h3>

<p>Months have passed now, and I’m back at <a href="https://tanzu.vmware.com/labs">Tanzu Labs</a>, happy to have had the time to help this amazing team and learn about Buildpacks internals. <br />
It was an amazing experience I’d try again in the future.</p>

<h2 id="some-of-my-contributions">Some of my contributions:</h2>
<ul>
  <li>Pack: <a href="https://github.com/buildpacks/pack/commits?author=dlion">https://github.com/buildpacks/pack/commits?author=dlion</a></li>
  <li>lifecycle: <a href="https://github.com/buildpacks/lifecycle/commits?author=dlion">https://github.com/buildpacks/lifecycle/commits?author=dlion</a></li>
  <li>samples: <a href="https://github.com/buildpacks/samples/commits?author=dlion">https://github.com/buildpacks/samples/commits?author=dlion</a></li>
  <li>imgutil: <a href="[https://github.com/buildpacks/imgutil/commits?author=dlion">https://github.com/buildpacks/imgutil/commits?author=dlion</a></li>
  <li>docs: <a href="[https://github.com/buildpacks/docs/commits?author=dlion">https://github.com/buildpacks/docs/commits?author=dlion</a></li>
  <li>RFCs: <a href="https://github.com/buildpacks/rfcs/commits?author=dlion">https://github.com/buildpacks/rfcs/commits?author=dlion</a></li>
</ul>

<p>I led and facilitated a <a href="https://tanzu.vmware.com/developer/practices/journey-map/">user journey mapping</a> session with some our users about a <a href="https://github.com/buildpacks/rfcs/pull/290">flatten feature</a>, it was really interesting getting feedback from our users, shaping the functionality based on their feedback and of course, I was happy to have put my facilitation skills to help the project.</p>

<p><img src="https://user-images.githubusercontent.com/2125236/257560685-b9a8a0b6-55f0-4074-a8d4-2d7baf6c4338.png" alt="user journey mapping" /></p>

<h2 id="outcome">Outcome</h2>

<p>I <strong>over-achieved</strong> the initial goal of delivering just one small feature, but I’ve got passionate about the project and, I couldn’t help myself delivering just one small thing, I wanted to have an impact and deliver as much value as possible to our users.</p>

<h2 id="become-a-contributor">Become a contributor</h2>

<ul>
  <li>If you want to start becoming a contributor don’t be shy and take any of the first-good-issue issues that already exist on any of the repos I linked above.</li>
  <li>Ask for help, the team is there to support you, and they will try to unblock you, they are the best! 💪🏻</li>
</ul>

<h2 id="thank-you">Thank you</h2>

<p>I’d like to thank:</p>
<ul>
  <li>VMware for the amazing opportunity.</li>
  <li>The CNB team has welcomed, helped, and supported me all the time: Natalie, Juan, Navdeep, Nanci and Joe.</li>
  <li>Labs managers that have approved my request for the Take3</li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>November 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/11/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/11/01/bookmarks.html</guid>
      <pubDate>Wed, 01 Nov 2023 00:00:00 +0100</pubDate><description>Bookmarks for November 2023: 13 links - Confusing git terminology; In a git repository, where do your files live?; Working without mocks - Learn Go with tests, and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://jvns.ca/blog/2023/11/01/confusing-git-terminology/">Confusing git terminology</a></li>
  <li><a href="https://jvns.ca/blog/2023/09/14/in-a-git-repository--where-do-your-files-live-/">In a git repository, where do your files live?</a></li>
  <li><a href="https://quii.gitbook.io/learn-go-with-tests/testing-fundamentals/working-without-mocks">Working without mocks - Learn Go with tests</a></li>
  <li><a href="https://ishan.page/blog/2023-11-06-jq-by-example/">The Ultimate Interactive JQ Guide</a></li>
  <li><a href="https://gomakethings.com/dont-disable-buttons/">Don’t disable buttons - Go Make Things</a></li>
  <li><a href="https://www.hillelwayne.com/post/lsp/">A better explanation of the Liskov Substitution Principle</a></li>
  <li><a href="https://lucasfcosta.com/2022/09/15/deadlines.html">Why deadlines are pointless and what to do instead</a></li>
  <li><a href="https://web.archive.org/web/20221128151220/https://sustainablepace.net/what-is-sustainable-pace">Sustainable Pace - What is Sustainable Pace?</a></li>
  <li><a href="https://www.sustainablepace.net/what-is-sustainable-pace">404 Not Found</a></li>
  <li><a href="https://aelaschool.com/en/userexperience/double-diamond-help-define-real-problem/">Double Diamond To Help Define What The Real Problem Is - Aela School</a></li>
  <li><a href="https://electronics.stackexchange.com/questions/623358/wouldnt-charging-a-lithium-battery-to-80-only-defeat-the-purpose-of-putting-th">batteries - Wouldn’t charging a lithium battery to 80% only defeat the purpose of putting the battery into longer use in the first place? - Electrical Engineering Stack Exchange</a></li>
  <li><a href="https://tidyfirst.substack.com/p/tdd-outcomes">TDD Outcomes - by Kent Beck - Software Design: Tidy First?</a></li>
  <li><a href="/note.html">New note</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>October 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/10/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/10/01/bookmarks.html</guid>
      <pubDate>Sun, 01 Oct 2023 00:00:00 +0200</pubDate><description>Bookmarks for October 2023: 4 links - The Absolute Minimum Every Software Develo...; Dependency Injection - Learn Go with tests, and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://tonsky.me/blog/unicode/">The Absolute Minimum Every Software Developer Must Know About Unicode in 2023 (Still No Excuses!) @ tonsky.me</a></li>
  <li><a href="https://quii.gitbook.io/learn-go-with-tests/go-fundamentals/dependency-injection">Dependency Injection - Learn Go with tests</a></li>
  <li><a href="https://quii.gitbook.io/learn-go-with-tests/go-fundamentals/mocking">Mocking - Learn Go with tests</a></li>
  <li><a href="https://howvideo.works/">howvideo.works</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>September 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/09/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/09/01/bookmarks.html</guid>
      <pubDate>Fri, 01 Sep 2023 00:00:00 +0200</pubDate><description>Bookmarks for September 2023: 11 links - Measuring developer productivity? A respon...; How to pass a coding interview with me - R..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://tidyfirst.substack.com/p/measuring-developer-productivity-440">Measuring developer productivity? A response to McKinsey 2</a></li>
  <li><a href="https://robertheaton.com/interview/">How to pass a coding interview with me - Robert Heaton</a></li>
  <li><a href="https://akashrajpurohit.com/blog/running-ssl-on-localhost/">Running SSL on Localhost</a></li>
  <li><a href="https://www.bautista.dev/reasons-to-not-use-your-own-domain-for-email">Reasons to not use your own domain for email - Eduardo Bautista</a></li>
  <li><a href="https://renegadeotter.com/2023/09/10/death-by-a-thousand-microservices.html">Death by a thousand microservices</a></li>
  <li><a href="https://renegadeotter.com/2023/07/26/i-am-not-your-cloud-person.html">I am not your Cloud person</a></li>
  <li><a href="https://tracyosborn.com/articles/hacking-your-week-the-28-hour-day/">Hacking your week: The 28 hour day</a></li>
  <li><a href="https://wejn.org/2023/09/running-ones-own-root-certificate-authority-in-2023/">Running one’s own root Certificate Authority in 2023</a></li>
  <li><a href="https://www.youtube.com/watch?v=2qpdjKWNwi0">(1) Lesson 25 - Architectural Abstraction - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=dNrF1tZf4Lk">Lesson 26 - Agile Architecture Review Boards - YouTube</a></li>
  <li><a href="https://stacking.dev/">The stacking workflow</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>August 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/08/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/08/01/bookmarks.html</guid>
      <pubDate>Tue, 01 Aug 2023 00:00:00 +0200</pubDate><description>Bookmarks for August 2023: 4 links - Don&apos;t be clever - stitcher.io; Perche&apos; l&apos;OnlyFans economy impatta sul mercato del lavoro...; Broken Ownership, and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://stitcher.io/blog/dont-be-clever">Don’t be clever - stitcher.io</a></li>
  <li><a href="https://keinpfusch.net/perche-onlyfans-impatta-sul-mercato-del-lavoro-italiano/">Perche’ l’OnlyFans economy impatta sul mercato del lavoro italiano. - Das Böse Büro</a></li>
  <li><a href="https://blog.alexewerlof.com/p/broken-ownership">Broken Ownership</a></li>
  <li><a href="/note.html">New note</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>July 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/07/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/07/01/bookmarks.html</guid>
      <pubDate>Sat, 01 Jul 2023 00:00:00 +0200</pubDate><description>Bookmarks for July 2023: 2 links - How to Learn Better in the Digital Age; Nobody cares about your blog..</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://giansegato.com/essays/edutainment-is-not-learning">How to Learn Better in the Digital Age</a></li>
  <li><a href="https://www.alexmolas.com/2023/07/15/nobody-cares-about-your-blog.html">Nobody cares about your blog.</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>How I Passed my AWS Certified Developer Exam</title>
      <link>https://domenicoluciani.com/2023/06/08/how-i-passed-my-aws-certified-developer-exam.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/06/08/how-i-passed-my-aws-certified-developer-exam.html</guid>
      <pubDate>Thu, 08 Jun 2023 00:00:00 +0200</pubDate><description>A few weeks ago I passed my AWS Certified Developer Associate (DVA-02) exam and I thought it would have been nice to document how _heck_ I accomplished to do it on a first try,…</description>
      <content:encoded><![CDATA[
<p>A few weeks ago <a href="https://domenicoluciani.com/2023/05/16/aws-certified-developer-associate-certification.html">I passed my AWS Certified Developer Associate (DVA-02) exam</a> and I thought it would have been nice to document how <em>heck</em> I accomplished to do it on a first try, and of course provide some hints to whoever wants to 
do the same. 🧑🏻‍💻👨🏻‍💻</p>

<hr />

<h2 id="but-why-did-you-spend-your-time-getting-the-certification">But why did you spend your time getting the certification?</h2>

<p>I’d like to start by saying that I’m not a big fan of getting as many certifications as possible, I’m more affected by the greedy learner pathology which pushed me forward on this route.</p>

<blockquote>
  <p>This indeed is my first real certification.</p>
</blockquote>

<p>I started to study AWS <strong>just for fun</strong> and to desire to become a better professional. <strong>I wasn’t really interested to get any certification.</strong> <br />
I started it for fun and it became even more fun over time, digging deeper into AWS services and use cases, so at the end of the path/course I felt that after all the effort I could try to challenge myself even more by getting the 
certification. <br />
<strong>I LOVE GOING OUTSIDE MY COMFORT ZONE</strong></p>

<blockquote>
  <p>Did I need it? No. <br />
Do you need it? Probably not.</p>
</blockquote>

<p>It was just a matter of challenging myself, nothing more 🤭 so my advice is to enjoy the journey and learn as much as possible but just for your own sake, it will give you the extra motivation you need to pass the exam at the first try. 🎯</p>

<h2 id="why-did-i-focus-on-aws">Why did I focus on AWS?</h2>

<p>I work at <a href="https://tanzu.vmware.com/labs">VMware Tanzu Labs</a> right now, and we often jump from one project to another; it’s always fun and it gives the possibility to work on different things and don’t get bored. 🤩 <br />
One thing that I noticed was that during my career I’ve always been facing AWS architectures at least once per year.</p>

<blockquote>
  <p>At least one client had their ecosystem on AWS.</p>
</blockquote>

<p>Working for a <a href="https://vmware.com">Multi-Cloud company</a> gives me the possibility to have a T-shape skills-set, focusing more on the <code>how</code>  than the <code>what</code>; I mean, I worked on Azure and GCP as well, but to be honest the most fun 
ecosystems I worked on were on AWS. 🤭</p>

<p>So I felt that I needed, for my career and for my interest (📚) to fill out some gaps that I had on AWS to become a better engineer and a better professional. 💪🏻</p>

<h2 id="where-did-i-study">Where did I study?</h2>

<h3 id="a-cloud-guru">A Cloud Guru</h3>

<p>Working at VMware also means I have lots of benefits 😌🙏 and one of them is the possibility to access <a href="https://acloudguru.com/">https://acloudguru.com/</a> courses/resources/labs <strong>FOR FREE</strong>! ✨ <br />
A Cloud Guru is well known to be very expensive but to have one of the best playgrounds out there.</p>

<h4 id="playground">Playground?</h4>

<p>Yes, essentially you can just go to their playground section <br />
Open a new session of their sandbox and log in.</p>

<p>From that moment till a bunch of hours, you will have the chance to play with an almost real AWS environment, bill-free. 👀</p>

<p><img src="/assets/images/posts/playground-aws-1.png" alt="playground-aws-1" /></p>

<h4 id="developer-associate-course">Developer Associate Course</h4>

<p>Of course, A Cloud Guru has its course: <a href="https://learn.acloud.guru/course/aws-certified-developer-associate">https://learn.acloud.guru/course/aws-certified-developer-associate</a> <br />
I took it and I can say that it covers more or less everything you need to know to pass the exam. <br />
Especially I want to call out the 4 mocked exams which have been super useful to get to know the exam env and the questions’ style.</p>

<p><img src="/assets/images/posts/mocked-exam-aws.png" alt="mocked-exam" /></p>

<h3 id="tutorials-dojo">Tutorials Dojo</h3>

<p>Another resource I found useful to reinforce my knowledge was <a href="https://tutorialsdojo.com/">https://tutorialsdojo.com/</a> <br />
It’s a website that contains a study path for each certification. <br />
Here the one for the Developer Associate: <a href="https://tutorialsdojo.com/aws-certified-developer-associate-exam-guide-study-path-dva-c02/"> https://tutorialsdojo.com/aws-certified-developer-associate-exam-guide-study-path-dva-c02/</a></p>

<h4 id="mocked-exams">Mocked Exams</h4>

<p>In Tutorials Dojo you can also find mocked exams which as far as I heard are very close to the real ones but I haven’t purchased it so I don’t have a personal opinion or experience on it.</p>

<h3 id="aws-whitepapers">AWS Whitepapers</h3>

<p>Listed either on Tutorials Dojo or A Cloud Guru you can find a list of recommended whitepapers from AWS that are worth reading. <br />
I know, they are quite big but I think that reading them once is worth your time.</p>

<h3 id="reddit">Reddit</h3>
<p>I also really liked reading about other experiences on <a href="https://www.reddit.com/r/AWSCertifications/">/r/AWSCertifications/</a>, it is full of nice advice and great people who can help you out. <br />
There I discovered that there are other recommended resources that I didn’t follow, maybe it’s worth having a look at it. 👀</p>

<h2 id="how-did-i-study">How did I study?</h2>

<blockquote>
  <p>Every person has their unique approach so there aren’t good or wrong ways to study.</p>
</blockquote>

<p>Having a full-time job it’s always complicated to find the time and the energy to study, for this reason, I repeat that you should study <em>only because you want to learn new things</em>, improve yourself and become a better professional. <br />
The certification itself IMHO doesn’t add anything up to your skills-set. <br />
I studied for 2 months more or less, dedicating myself to it almost every day for at least 25 minutes.</p>

<blockquote>
  <p>Something I would like to highlight here is that <strong>I have more than 10 years of experience</strong> as a Software Engineer so your experience can be different and you might need more time and resources.</p>
</blockquote>

<h3 id="obsidian">Obsidian</h3>

<p><a href="https://obsidian.md">Obsidian</a> is my main tool for taking notes, creating blog posts, scheduling my day, keeping track of everything, and of course: studying. <br />
<a href="https://domenicoluciani.com/2021/12/17/why-did-i-switch-from-notion-to-obsidian.html">I switched over to Obsidian from Notion</a> and I will never get back to it. <br />
My main way to study is to take notes about whatever I read/watch and then look at it later on, to memorise better and freshener those concepts. <br />
Spatial repetition works very well for me even tho I’m not very consistent.</p>

<h3 id="excalidraw">Excalidraw</h3>

<p>Another amazing tool I’ve been using to memorise better is <a href="https://excalidraw.com/">Excalidraw</a>, an infinite canvas that I used to divide each topic with its information. <br />
It has been very useful to visualise the information that I’ve got from the video course and blog posts.</p>

<p>Worth to mention that Obsidian has an <a href="https://github.com/zsviczian/obsidian-excalidraw-plugin">Excalidraw plugin</a> which means you can use all Excalidraw functionalities from your Obsidian instance, having your draws locally.</p>

<p>For me having a visual representation works quite well and it helps to remember better.</p>

<p><img src="/assets/images/posts/excalidraw-aws.png" alt="excalidrw-aws" /></p>

<h3 id="mocked-exams-1">Mocked Exams</h3>

<p>As mentioned before doing mocked exams <strong>IS KEY</strong> to pass your exam, it helps you to get familiar with the questions and the timing.</p>

<h4 id="strategy-i-adopted">Strategy I adopted</h4>

<p>A Cloud Guru gives you 4 exams that you can practice with.</p>

<p>My strategy was:</p>
<ol>
  <li>Take the mocked exam</li>
  <li>Review the questions I’ve answered wrongly</li>
  <li>Take notes of the wrong answers</li>
  <li>Read deeper about that specific topic by going through the AWS documentation</li>
  <li>Read again what I did wrong</li>
  <li>Re-take the exam</li>
</ol>

<p>My goal was to pass each mocked exam with at least 80% of correct answers. <br />
I’ve done it multiple times during the 2 months I spent studying. <br />
Don’t focus too much on the specific questions but more on the topics they cover.</p>

<h3 id="hands-on-lab">Hands-on Lab</h3>

<p>A Cloud Guru helps a lot with the hands-on part but it doesn’t mean you can’t open an AWS free-tier account and try by yourself to play with AWS services. <br />
Right now the exam is composed of 65 multi-choice questions so at first it seems not hands-on oriented but that would be the wrong assumption. <br />
Lots of questions are about specific technical details and particular services options that it’s easier to know if you had the chance to play with them and having a hands-on experience is always better considering the 
nature of this certification.</p>

<h2 id="final-thoughts">Final thoughts</h2>

<p>Coming to the end of the article, I’d like to say again that I think that the certification per se says nothing about your competencies and skill set. <br />
Yeah, it shows other people that you can stick to a plan, go out of your comfort zone and that you are capable of learning new things. <br />
I’ve been a software engineer for more than 10 years so far, and I can say that having a certification doesn’t mean you are a better professional than those who don’t have it.</p>

<h5 id="friendly-reminder">Friendly reminder:</h5>

<p>Don’t be too hard on yourself, if you don’t pass the exam, if you don’t complete the course or if you drop it after a few months. <br />
Keep trying, keep being motivated thinking about what you are learning more than what you can do with the certification.</p>

<p>Good Luck! 🍀</p>

      ]]></content:encoded>
    </item><item>
      <title>June 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/06/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/06/01/bookmarks.html</guid>
      <pubDate>Thu, 01 Jun 2023 00:00:00 +0200</pubDate><description>Bookmarks for June 2023: 9 links - (2) Lesson 21 - Integration Styles: Remote Procedure Call...; Lesson 22 - Integration Styles: Messaging - YouTube; Some blogging myths, and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://www.youtube.com/watch?v=OGgbajZNwpU">(2) Lesson 21 - Integration Styles: Remote Procedure Call - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=Oq5VP0cKwXI">Lesson 22 - Integration Styles: Messaging - YouTube</a></li>
  <li><a href="https://jvns.ca/blog/2023/06/05/some-blogging-myths/">Some blogging myths</a></li>
  <li><a href="https://www.youtube.com/watch?v=cYENNwDK2dA">Lesson 23 - Orchestration vs Choreography - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=WP60uc0JXjk">Lesson 24 - Lean Modeling Concepts - YouTube</a></li>
  <li><a href="https://blog.yoshuawuyts.com/what-is-wasi/">What is WASI?</a></li>
  <li><a href="https://www.youtube.com/watch?v=SK6e_ZatOaw">(3) Intro to Cloud Native Buildpacks - Terence Lee, Heroku &amp; Emily Casey, Pivotal - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=Mi_fb5ToOa8&amp;themeRefresh=1">youtube.com/watch?v=Mi_fb5ToOa8&amp;themeRefresh=1</a></li>
  <li><a href="https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/">Gopher Wrangling. Effective error handling in Go - Stephen’s Tech Blog</a></li>
</ul>

      ]]></content:encoded>
    </item><item>
      <title>I&apos;ve got the AWS Certified Developer Associate - Certification</title>
      <link>https://domenicoluciani.com/2023/05/16/aws-certified-developer-associate-certification.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/05/16/aws-certified-developer-associate-certification.html</guid>
      <pubDate>Tue, 16 May 2023 00:00:00 +0200</pubDate><description>🎉 I am thrilled to share that I have recently achieved my AWS Certified Developer – Associate certification! ☁️🧑🏻‍💻</description>
      <content:encoded><![CDATA[
<p>🎉 I am thrilled to share that I have recently achieved my AWS Certified Developer – Associate certification! ☁️🧑🏻‍💻</p>

<p>It’s been a fun and rewarding journey, enhancing my expertise in building cloud-native applications with AWS services! ☁️🔭</p>

<div data-iframe-width="700" data-iframe-height="270" data-share-badge-id="8f35d087-b608-48a4-9c72-36dc29ac6c92" data-share-badge-host="https://www.credly.com"></div>
<script type="text/javascript" async="" src="//cdn.credly.com/assets/utilities/embed.js"></script>


      ]]></content:encoded>
    </item><item>
      <title>Safeguarding Software: Embracing Security Design Principles in Software Development</title>
      <link>https://domenicoluciani.com/2023/05/04/safeguarding-software-security-design-principles.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/05/04/safeguarding-software-security-design-principles.html</guid>
      <pubDate>Thu, 04 May 2023 00:00:00 +0200</pubDate><description>In today&apos;s digital landscape, developing software with a security-oriented mindset is no longer an option – it&apos;s a top priority. I&apos;ve had the opportunity to attend the Secure…</description>
      <content:encoded><![CDATA[
<p>In today’s digital landscape, developing software with a security-oriented mindset is no longer an option – it’s a top priority. <br />
I’ve had the opportunity to attend the <a href="https://training.linuxfoundation.org/training/developing-secure-software-lfd121/">Secure Software Development Fundamentals Course</a> by the <a href="https://openssf.org/">Open Source Security Foundation</a>, and I found it enlightening and a must for passionate Software Engineers. <br />
So today, I’m going to talk about a set of widely recommended Security Design Principles that serve as invaluable rules of thumb for developing software with security-first in mind. <br />
Let’s start! 🚀</p>

<hr />

<h1 id="least-privilege">Least Privilege</h1>

<p>Probably the most well-known principle, I’m talking about the <code>Least Privilege</code> design principle. <br />
This principle revolves around the concept of giving just the required privileges to a specific user/application to operate correctly, which means with <strong>the fewest privileges possible</strong>. <br />
Following this principle makes unintentional or improper uses of privilege less likely to occur.</p>

<p>A few points to remember 👇</p>

<ul>
  <li>Don’t give a user/application any special privileges if they are not needed.</li>
  <li>Always minimize the special privileges a user/program receives.</li>
  <li>Give up privileges as soon as they are no longer required.</li>
  <li>If it’s not possible to give up privileges, try to limit the time the privilege is active.</li>
  <li>Break your application into different modules and give special privileges - if needed - to only a few modules.</li>
  <li>Minimize the attack surface.</li>
  <li>Validate the input before accepting it.</li>
  <li>Sandbox your application, running it in an intentionally restricted environment.</li>
  <li>Minimize privileges for files and other resources.</li>
</ul>

<p><img src="https://media.giphy.com/media/Hn1VPQRmzEZUc/giphy.gif" alt="least privilege" /></p>

<h1 id="complete-mediation">Complete Mediation</h1>

<p>This principle is often called the <code>non-bypassability</code> principle. Essentially, it states that every access attempt coming from an external domain should be checked, and especially, don’t act on the data received before validating that the request came from a valid source. <br />
By following this principle, we have thorough and consistent authorization checks at every access point in a software system, protecting data and enhancing the security of our application.</p>

<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMjFmYWQwZDQ5MmFmZGU1NWU3YzIxYzEzOGFhYjRmMTA3MDQ2MGViOSZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/IeKgCDlpTqRQbZEhBF/giphy.gif" alt="check" /></p>
<h1 id="economy-of-mechanism">Economy of Mechanism</h1>

<p>This is the <code>simplicity</code> principle, also called KISS. <br />
Security and over-engineering are always a dangerous duo. Having a security mechanism with lots of hidden features and intricate components can increase the chances of something going wrong. <br />
The rule to follow this principle is to keep your security mechanism simple. Don’t try to reinvent the wheel or overcomplicate the solution – <strong>keep it simple</strong>. <br />
A simple system is easier to review, maintain, and test, and harder to get wrong.</p>

<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZDc5Y2EzOTUyOGNhYTYwOTE1NDk5MzE3MmQ3NTk0MzA3ZjdjODNlNSZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/3o6Mbsras7qdAwgABW/giphy.gif" alt="complex" /></p>

<h1 id="open-design">Open Design</h1>

<p>The Open Design principle is often underestimated, but it’s one of the most powerful. <br />
Essentially, it states that an attacker shouldn’t be able to break into our system just because they know how it works. Relying on the ignorance of the attacker to protect our system is always a big mistake. <br />
We should always act as if the security mechanism is publicly known and depend on the secrecy of a few easily changeable items like credentials. <br />
The opposite of the Open Design principle is called <a href="https://en.wikipedia.org/wiki/Security_through_obscurity">Security Through Obscurity</a>, and there have been multiple documented cases that prove it doesn’t work. <br />
Moreover, having an open design makes extensive public scrutiny possible and gives confidence to any user who knows about the mechanism used that our software is secure.</p>

<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExOWIwOWQzYjJhM2I3ZGQ4NTVhOWJiZjM5NzNlYjM3YjM5NGFjNTRhNyZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/17DxVYqrlsbSDWiPeA/giphy.gif" alt="open design" /></p>

<h1 id="fail-safe-defaults">Fail-Safe Defaults</h1>

<p>The rule of this principle is that in situations where a decision or authorization cannot be explicitly determined, the system should default to the most secure option. <br />
Don’t distribute software with an empty or default password; instead, force the user to set it up during the installation process. <br />
How many times have you seen default passwords being used by unaware users? By applying this principle, developers can minimize the risks associated with incomplete or erroneous authorization decisions.</p>

<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMzBiOGJjY2RjMjdjMmMwZWE0Y2E3YjkxZjVmMmM3N2FjMGI2MzI4NyZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/3ogwGakzdnTxvRgxfG/giphy.gif" alt="safe" /></p>

<h1 id="separation-of-privilege">Separation of Privilege</h1>

<p>This principle states that access to critical resources or sensitive operations should depend on more than one independent condition. In this way, even if an attacker manages to break one condition, they still need to break the others to compromise the system’s security. <br />
It promotes the distribution of privileges and responsibilities to multiple independent entities, reducing the potential impact of compromised accounts.</p>

<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYWYzYTRiZDRlN2Q5ZTdlNTFjN2U3MzlhNzIxN2JhYmE2NTg1ZTA0NyZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/kQYNaEa35hQ6pCYywH/giphy-downsized-large.gif" alt="powers" /></p>

<h1 id="least-common-mechanism">Least Common Mechanism</h1>

<p>This principle focuses on reducing the amount of shared resources or dependencies between different components of a system. In some cases, sharing can reduce costs, but it increases security risks. <br />
Following this principle leads to having more modular and robust software. For example, we can establish separate database connections for different components or modules instead of using a single, shared one. This approach minimizes the chances of conflicts or bottlenecks and allows for better isolation and scalability.</p>

<p><img src="https://media.giphy.com/media/llToceLTKQj0R1Asid/giphy.gif" alt="don't share" /></p>

<h1 id="psychological-acceptability">Psychological Acceptability</h1>

<p>This principle is more user-centric. It states that the security mechanism’s user interface must be designed to be user-friendly and simple to use. <br />
If something is hard to use, it is often insecure in practice because users will work around it to make their lives easier. <br />
One easy example is defining rules for passwords; after a few attempts, users will resort to using very simple passwords just to pass all the checks and move on, causing the opposite effect.</p>

<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExOTY2NTkzMmE3ZjZiOTBmZGZjMTYwYzNkNDY1ODRmZjM3MDdmYWQ0MSZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/gj0IKRLgBFap2TlcoD/giphy.gif" alt="nope" /></p>

<h1 id="conclusion">Conclusion</h1>

<p>These security design principles are not mere theoretical concepts; they provide practical guidelines that can be applied during the software development lifecycle, which, for me, is <strong>GOLD</strong>.</p>

<p>Of course, these security design principles are guidelines, and there may be good reasons not to apply them in some cases. It is important to think about them wisely and consider the specific context of your software development project.</p>

<p><img src="https://media.giphy.com/media/d3mlE7uhX8KFgEmY/giphy.gif" alt="think" /></p>

<p>Remember, security is an ongoing process. We must remain vigilant, continuously assess our systems, and act accordingly.</p>

<p>As software engineers, we have the <strong>responsibility</strong> to build software that not only meets functional requirements but also prioritizes the protection of user privacy, data integrity, and system reliability.</p>

      ]]></content:encoded>
    </item><item>
      <title>May 2023 - Bookmarks</title>
      <link>https://domenicoluciani.com/2023/05/01/bookmarks.html</link>
      <guid isPermaLink="true">https://domenicoluciani.com/2023/05/01/bookmarks.html</guid>
      <pubDate>Mon, 01 May 2023 00:00:00 +0200</pubDate><description>Bookmarks for May 2023: 17 links - An Architecture Path to Mainframe Moderniz...; (11) Lesson 9 - Analyzing Architecture: Ma..., and more.</description>
      <content:encoded><![CDATA[
<ul>
  <li><a href="https://tanzu.vmware.com/content/blog/architecture-path-to-mainframe-modernization">An Architecture Path to Mainframe Modernization</a></li>
  <li><a href="https://www.youtube.com/watch?v=h1So8tVukS8">(11) Lesson 9 - Analyzing Architecture: Macro Techniques - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=U7s7Hb6GZCU">(25) Lesson 10 - Analyzing Architecture: Microservices - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=pELKNy8B5Nw">(26) Lesson 11 - Analyzing Architecture: Code Metrics - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=2VDDA6BvcAo">(28) VDZ22 Achieving an evolutionary architecture through simplicity by Urs Enzler - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=pUGvXUBfvEE">(30) Lesson 12 - CQRS and Microservices - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=n_7PCFkxPPw">(1) Lesson13 - Microservices and Reporting - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=DKPn0AcvLKo">(13) Lesson14 - Refactoring Patterns: Migration vs. Adaptation - YouTube</a></li>
  <li><a href="https://hashrust.com/blog/a-guide-to-closures-in-rust/">A guide to closures in Rust</a></li>
  <li><a href="https://www.youtube.com/watch?v=RefvolwEOIc">Lesson 16 - The Challenges of Architecture Teams - YouTube</a></li>
  <li><a href="https://martinfowler.com/articles/mocksArentStubs.html">Mocks Aren’t Stubs</a></li>
  <li><a href="https://martinfowler.com/bliki/TellDontAsk.html">TellDontAsk</a></li>
  <li><a href="https://www.youtube.com/watch?v=52haYbu80e8">(13) Lesson 17 - Architecture Tradeoffs - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=UZxLYv5RFyI">(13) Lesson 18 - The Fallacies of Distributed Computing - YouTube</a></li>
  <li><a href="https://hbr.org/2023/05/to-improve-your-work-performance-get-some-exercise">To Improve Your Work Performance, Get Some Exercise</a></li>
  <li><a href="https://www.youtube.com/watch?v=_uRYlUuxjVA">Lesson19 Integration Styles: File Transfer - YouTube</a></li>
  <li><a href="https://www.youtube.com/watch?v=CSAFJNoT34M">Lesson 20 - Integration Style: Shared Database - YouTube</a></li>
</ul>

      ]]></content:encoded>
    </item></channel>
</rss>

