<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on  rlang // tech</title>
    <link>https://blog.rlang.tech/posts/</link>
    <description>Recent content in Posts on  rlang // tech</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>Rico Lang (CC BY 4.0)</copyright>
    <lastBuildDate>Fri, 05 Sep 2025 23:34:00 +0200</lastBuildDate>
    <atom:link href="https://blog.rlang.tech/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The Joy of Test Driven Development</title>
      <link>https://blog.rlang.tech/posts/the-joy-of-test-driven-development/</link>
      <pubDate>Fri, 05 Sep 2025 23:34:00 +0200</pubDate>
      <guid>https://blog.rlang.tech/posts/the-joy-of-test-driven-development/</guid>
      <description>&lt;img src=&#34;tdd.png&#34; alt=&#34;TDD cycle&#34;&gt;&lt;p&gt;At the moment I&amp;rsquo;m working on a project where I&amp;rsquo;m more of a YAML engineer than anything else. During this time, I kind of enjoy getting my hands on actual code again, but most of the time, writing code is a rarity for me. So, whenever I find a cool idea to work on, I usually start a new side project. Something I try to incorporate as soon as possible is &lt;strong&gt;Test Driven Development (TDD)&lt;/strong&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<img src="tdd.png" alt="TDD cycle"><p>At the moment I&rsquo;m working on a project where I&rsquo;m more of a YAML engineer than anything else. During this time, I kind of enjoy getting my hands on actual code again, but most of the time, writing code is a rarity for me. So, whenever I find a cool idea to work on, I usually start a new side project. Something I try to incorporate as soon as possible is <strong>Test Driven Development (TDD)</strong>.</p>
<p>While I agree that initially TDD may not fit into the ideation phase of your
project where you&rsquo;re still trying to figure what you&rsquo;re doing, but as soon as you&rsquo;re evolving TDD really speeds up your
development.</p>
<p>Let me show you how TDD can up your coding game ! 🚀</p>
<h2 id="refactoring-becomes-part-of-your-workflow">Refactoring Becomes Part of Your Workflow</h2>
<p>While I was working on my side project, something I immediately noticed after applying TDD to it was that refactoring became a part of my development workflow. That&rsquo;s a great thing, right? I mean, how many times have you looked at code thinking:</p>
<blockquote>
<p>&ldquo;Damn
that thing should&rsquo;ve been
refactored a long time ago&rdquo;.</p>
</blockquote>
<p>With TDD, you&rsquo;re refactoring your code more often, simply because you&rsquo;re wiring it directly into your workflow. Every test you write forces you to think about the design of your code, and since writing tests has now become a first-class citizen in your code, you&rsquo;re more likely to refactor your code so that it remains easy to test.</p>
<h2 id="shorter-feedback-cycles">Shorter Feedback Cycles</h2>
<p>By practicing TDD, you&rsquo;re forcing yourself into a constant feedback loop, iterating on the implementation and the design of the code. By writing the test first, you&rsquo;re already investing in the design because you have to think about what your function will return, whether it has a side effect you need to capture, and so on. This leaves you with code that is testable right from the start and easy to refactor later on, since you already have tests covering your existing functionality. As you&rsquo;re in a constant cycle of writing a test, implementing the functionality, and refactoring your code, your feedback loop is way shorter than writing the implementation, starting up the application, and refactoring/fixing bugs afterward.</p>
<h2 id="less-cognitive-complexity">Less cognitive complexity</h2>
<p>Test-driven development encourages you to think about one thing at a time, which really helps to reduce the cognitive complexity during the implementation and while reading the code. More often than not, we get assigned features that contain a lot of business rules, errors, and edge cases. Keeping track of all those things during development can be a real pain.</p>
<p>TDD can help you manage this complexity. If done properly, the acceptance criteria of your feature directly translate to the tests you write. So, in a test-driven fashion, you start writing a test for your first acceptance criterion, implement it, and move on to the next one. This way, you can focus on one part of your feature at a time, and you don&rsquo;t have to worry about introducing yet another edge case, since your tests have your back right from the beginning. If you don&rsquo;t use TDD, you might be inclined to implement all the acceptance criteria at once, thus putting a huge load on your brain.</p>
<h2 id="separating-business-logic-from-side-effects">Separating Business Logic from Side Effects</h2>
<p>Another benefit of Test Driven Development that I absolutely love is that it forces you to keep your business logic <a href="https://en.wikipedia.org/wiki/Pure_function">pure</a> and keeps the side effects on the edges of your application. Side-effectful code can really be a nightmare to test or debug, as it does things you might not expect it to do.</p>
<p>Since TDD enforces your code to be testable, naturally, you tend to push side-effectful code, such as network requests, to the edges of your application so that your business logic is deterministic.</p>
<h2 id="tldr">TL;DR</h2>
<p>Test-driven development is obviously not a silver bullet, and it has to fit your development workflow. In most cases, I think TDD brings a lot to the table and will generally produce better code.</p>
<p>In essence, I&rsquo;d suggest you give it a try, since there is much to gain and not much to lose anyway. Take a <a href="https://kata-log.rocks/tdd">kata</a> and check it out!</p>
]]></content:encoded>
    </item>
    <item>
      <title>On enabling an unexperienced Product Owner</title>
      <link>https://blog.rlang.tech/posts/on-enabling-unexperienced-an-po/</link>
      <pubDate>Sun, 16 Mar 2025 11:13:05 +0100</pubDate>
      <guid>https://blog.rlang.tech/posts/on-enabling-unexperienced-an-po/</guid>
      <description>Did you ever an experience a time, where you did feel that you really had to drag along your PO, because they themselves didn&amp;rsquo;t properly fill the role ? I recently found myself in such a situation, thats what i learned from it.</description>
      <content:encoded><![CDATA[<p>Have you ever found yourself in a situation where you felt like you had to drag your Product Owner along because
they weren&rsquo;t fully owning their role?</p>
<p>I recently experienced this firsthand, growing increasingly frustrated with a product Owner in my project not performing
their duties as expected.</p>
<h1 id="have-some-empathy">Have Some Empathy</h1>
<p>While I&rsquo;ve never been a Product Owner myself, I can only imagine the challenge of bridging the gap between the business
and technical worlds. From a developer&rsquo;s perspective, a Product Owner&rsquo;s job might seem straightforward: a few meetings
here, some prioritization there, preparing for the next sprint. Sounds easy, right?</p>
<p>As simple as it might sound, being a PO demands significant skill and, most importantly, experience. You need a deep
understanding of the business domain and its goals. You must weigh the importance of meeting deadlines against the risk
of accumulating too much technical debt. On top of that, you&rsquo;re responsible for managing diverse stakeholders: managers,
end-users, and your own development team.</p>
<p>If you take on their hat for a second it can really help you understand what kind of work they have to do.
So the best way to start empowering your Product Owner is by <strong>showing empathy</strong> and striving to understand their
challenges.</p>
<h1 id="your-product-owner-is-a-team-member">Your Product Owner is a Team Member</h1>
<blockquote>
<p>Business people and developers must work together daily throughout the project.</p>
</blockquote>
<p>Too often, I observe teams treating their Product Owners as if they are managers or some kind of higher authority.
However, if we recall a key quote from the Agile Manifesto, it&rsquo;s clear that business people and developers are meant to
collaborate closely, so might as well treat them like a team member :) .</p>
<h1 id="practical-ways-to-help">Practical Ways to Help</h1>
<p>Here are some actionable steps you can take to support your Product Owner:</p>
<ul>
<li>
<p><strong>Communicate Effectively:</strong> As a senior engineer, you should maintain close and direct communication with your
Product Owner. Most problems a development team faces can be solved through open dialogue. If possible, set up regular
one-on-one sessions to foster a strong working relationship.</p>
</li>
<li>
<p><strong>Exchange Constructive Feedback:</strong> Giving and receiving feedback is one of the most powerful tools in your
professional career. It not only helps your peers and team members grow but also provides ample opportunities for your
own development. Use honest feedback to highlight areas where the team feels unsupported and suggest how your Product
Owner can better assist.</p>
</li>
<li>
<p><strong>Lend a Hand:</strong> Although it might not be explicitly your job, pairing with your Product Owner — for example, on
writing tickets or preparing for planning sessions — can be incredibly beneficial. Both of you can gain valuable
insights into how the other side operates and what people need to accomplish their work.</p>
</li>
<li>
<p><strong>Be Transparent:</strong> Transparency is another crucial factor in enabling your Product Owner. They most likely have
deadlines to meet, so be upfront about any blockers, dependencies, bugs, or other issues. Highlighting these early gives
your Product Owner the opportunity to adjust plans or manage stakeholder expectations effectively.</p>
</li>
</ul>
<h1 id="summary">Summary</h1>
<p>While none of these tips are revolutionary and might not apply to every person or situation, I believe these are the
most effective actions you can take to build a stronger relationship with your Product Owner, thereby empowering them to
excel in their role.</p>
<p><strong>TLDR:</strong> Don&rsquo;t work against each other; <strong>work with each other!</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>How to run Docker on IPv6</title>
      <link>https://blog.rlang.tech/posts/docker-on-ip-v6/</link>
      <pubDate>Mon, 20 Jan 2025 20:18:32 +0100</pubDate>
      <guid>https://blog.rlang.tech/posts/docker-on-ip-v6/</guid>
      <description>Overcoming IPv6 challenges with Docker? This tutorial shows you how to seamlessly run Docker containers on an IPv6-only host, enabling you to leverage the benefits of IPv6 networking.</description>
      <content:encoded><![CDATA[<p>When running Docker on an IPv6 only host it can be quite complicated to set it up properly. This blog post will help you
to get your container running on an IPv6 only infrastructure and avoid the most common gotchas.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>An IPv6 global prefix</li>
<li>Root permissions on the host</li>
</ul>
<h2 id="a-word-of-caution">A word of caution</h2>
<p>The first thing to note is that running on an IPv6 only host, it means that only v6 networking is generally possible.
So any communication running over v4 won&rsquo;t be possible. For example lets try DNS resolution. If I try to get the IP for
google.com on my IPv6 host I get the following response:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ dig www.google.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; ANSWER SECTION:
</span></span><span style="display:flex;"><span>www.google.com.		217	IN	A	142.250.186.68
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; Query time: <span style="color:#ae81ff">0</span> msec
</span></span><span style="display:flex;"><span>;; SERVER: 2a01:4ff:ff00::add:2#53<span style="color:#f92672">(</span>2a01:4ff:ff00::add:2<span style="color:#f92672">)</span> <span style="color:#f92672">(</span>UDP<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>...</span></span></code></pre></div><p>One thing we can immediately see is, that the DNS server that answered our request has an IPv6 address, but what happens
now if
I tell dig to resolve the query via an IPv4 DNS server ?</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ dig @1.1.1.1 www.google.com
</span></span><span style="display:flex;"><span>;; communications error to 1.1.1.1#53: timed out</span></span></code></pre></div><p>The request timed out as we expected because our host is not capable of using the IPv4 protocol. The same behavior will
be observable in our Docker containers unless we explicitly tell Docker to run in IPv6 mode. So, let&rsquo;s get going!</p>
<h2 id="configure-the-docker-daemon">Configure the docker daemon</h2>
<p>To configure the daemon(assuming you use dockerd), we need to edit the <code>daemon.json</code>. On linux hosts you can find the
file under <code>/etc/docker/daemon.json</code>, if you&rsquo;re running on another system consult
the <a href="https://docs.docker.com/engine/daemon/">documentation</a> of docker engine. If the file does not exist simply create
it.</p>
<p>In order to fix the problem with the DNS resolution we need to tell the daemon to use IPv6 DNS servers. In this scenario
I provided cloudflares DNS server. Additionally, we also instruct the daemon to enable v6 networking, as well as
creating
the default network with <a href="https://en.wikipedia.org/wiki/Unique_local_address">ULA</a> addresses.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;IPv6&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;fixed-cidr-v6&#34;</span>: <span style="color:#e6db74">&#34;fd00:dead:beef::/48&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;dns&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;2606:4700:4700::1111&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;2606:4700:4700::1001&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;ip6tables&#34;</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h2 id="retrieving-the-prefix">Retrieving the prefix</h2>
<p>To make your container globally reachable, we have to create an IPv6 network based on the global prefix of your host. In
simplified terms, the global prefix is a 48-bit unique prefix that is used to route packets to your network. To find
your IPv6 global prefix, you can execute <code>ip -6 addr show</code>. You want to search for a similar entry like this:</p>





<pre tabindex="0"><code>2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
   ...
    inet6 2a01:4f8:1c0c:66b3::1/64 scope global noprefixroute
       valid_lft forever preferred_lft forever
   ...</code></pre><p>As you can see, my hoster assigned me a /64 prefix. That means that the first 64 bits of the IPv6 address are fixed. So,
in my example, <code>2a01:04f8:1c0c:66b3</code> is the fixed part. If we would fully write out the IP, it would look like this <code>2a01: 04f8:1c0c:66b3:0000:0000:0000:0001</code>.</p>
<h2 id="creating-the-ipv6-network">Creating the IPv6 network</h2>
<p>Now let&rsquo;s choose a smaller subnet for our public network. For example lets choose a /80 subnet like
<code>2a01:4f8:1c0c:66b3:1::/80</code> . This will ensure containers in that network will receive a globally routable address,
which means that those containers can be reached from the outside, unless blocked by a firewall or something similar.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker network create --IPv6 --subnet 2a01:4f8:1c0c:66b3:1::/80 public</span></span></code></pre></div><h2 id="run-your-container">Run your container</h2>
<p>Last but not the least run a container and attach it to our public network:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>docker run --rm --network public -p <span style="color:#f92672">[</span>::<span style="color:#f92672">]</span>:8080:80 traefik/whoami</span></span></code></pre></div><p>And if we now have a look at our container it has been assigned a globally routable IPv6 address. That we can reach from
the internet.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker inspect 31cb810f7c00
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;Networks&#34;</span>: <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">&#34;public&#34;</span>: <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                    ...
</span></span><span style="display:flex;"><span>                    <span style="color:#e6db74">&#34;IPv6Gateway&#34;</span>: <span style="color:#e6db74">&#34;2a01:4f8:1c0c:66b3:1::1&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#e6db74">&#34;GlobalIPv6Address&#34;</span>: <span style="color:#e6db74">&#34;2a01:4f8:1c0c:66b3:1::3&#34;</span>,
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>...</span></span></code></pre></div>]]></content:encoded>
    </item>
  </channel>
</rss>
