<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://kukicola.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://kukicola.io/" rel="alternate" type="text/html" /><updated>2026-05-25T14:55:30+00:00</updated><id>https://kukicola.io/feed.xml</id><title type="html">kukicola.io - Software engineer writing about backend, infrastructure, AI, and open source.</title><subtitle>Software engineer writing about backend, infrastructure, AI, and open source.</subtitle><entry><title type="html">Don’t let AI burn you out</title><link href="https://kukicola.io/posts/dont-let-ai-burn-you-out/" rel="alternate" type="text/html" title="Don’t let AI burn you out" /><published>2026-05-25T00:00:00+00:00</published><updated>2026-05-25T00:00:00+00:00</updated><id>https://kukicola.io/posts/dont-let-ai-burn-you-out</id><content type="html" xml:base="https://kukicola.io/posts/dont-let-ai-burn-you-out/"><![CDATA[<p>Recent months have been crazy. AI changed software engineering and there is no way to escape it.
Productivity growing exponentially, small teams beating huge companies, new models emerging every day.
It’s a major shift in the way we work.</p>

<p>Unfortunately, it brings a lot of challenges. Experts on X telling you you’re being left behind if you’re not running 10
sessions at once. Code quality dropping to the ground. Constant exhaustion from context switching. It’s a clear path to
burnout. I’ve seen it myself - on me and on my team.</p>

<p>But it doesn’t have to be this way. Over the last few months I’ve adjusted how I work with AI -
how many agents I run, when I look at them, what I let interrupt me - and the chaos got manageable.</p>

<h2 id="dont-go-in-at-the-deep-end">Don’t go in at the deep end</h2>

<p>Let’s say it out loud: <strong>it’s ok to work on one thing at a time</strong>. AI makes you way more productive than ever even
without running multiple agents at once.</p>

<p>The fastest way to burn out is to jump straight to ten sessions before you can run one well. You end up babysitting all
of them, reviewing code you don’t fully understand, and feeling busier than ever while quality slowly drops.</p>

<p>Before scaling up, learn how to work with a single agent efficiently - without constantly interfering or guiding it.
Your agent should be able to take a task from start to finish on its own. There are many ways to achieve this: proper
<code class="language-plaintext highlighter-rouge">CLAUDE.md</code>/<code class="language-plaintext highlighter-rouge">AGENTS.md</code> files, clear prompts, related skills, linters, plan mode and so on. The single highest-leverage
habit is the simplest one: <strong>every time your agent makes a mistake, add a rule that prevents it from happening again.</strong>
That’s how the agent gets trustworthy over time.</p>

<p>If you feel like you’re wasting time waiting for the AI to finish, try fast mode (available in Codex for 2x tokens or in
Claude as extra usage). But fix the autonomy problem first - going faster doesn’t help if you’re still in the loop on
every decision.</p>

<h2 id="scaling-up">Scaling up</h2>

<p>Once your agent can run a task end-to-end without you, you’re ready to add more. Four things made the difference for me:
scaling slowly, planning my day in advance, killing the noise, and using a real orchestrator.</p>

<h3 id="scale-slowly">Scale slowly</h3>

<p>Don’t jump from one session to ten. Start with two. Then maybe three. If you can keep them running without losing track
of what either is doing, add another. If you can’t, drop back for a few more days. The right number is personal - some
people max out at three, others run eight. Find yours, don’t copy someone else’s.</p>

<h3 id="plan-your-switches">Plan your switches</h3>

<p>Constant <strong>context switching is a real problem</strong> - and it’s nothing new. Before AI, I hit it as I took on more
responsibilities: reviewing CVs, conducting interviews, code reviews, finishing my own tasks. What pulled me out was
time-blocking my day in advance, and the same principle works for AI sessions.</p>

<p>I start all my sessions at the same time, and I make sure each agent has everything it needs to run end-to-end. Then I
don’t look at them - I move on to whatever’s next on my list: reviews, emails, my own coding. I don’t care if a session
fails or finishes early. It can wait. It’s not going to starve. I check them when it’s their turn in my plan, not when
they ping me.</p>

<h3 id="reduce-the-noise">Reduce the noise</h3>

<p>AI didn’t invent notification overload, but it cranked it up by 100x. Every agent wants to ping you the moment it’s
done. Every PR comment, every CI failure, every Slack message competes for the same attention. <strong>Don’t turn async into
sync.</strong></p>

<p>The fix is mechanical: turn the notifications off. Agent pings, PR comments, channel messages - anything that isn’t
urgent. The only thing allowed to interrupt me is production on fire.</p>

<p>Here’s a dumb analogy: you’re chopping vegetables for soup. Someone asks you to also peel a potato. You don’t stop
mid-cucumber - unless the kitchen is on fire, the potato can wait.</p>

<h3 id="use-proper-tools">Use proper tools</h3>

<p>Running multiple agents from separate terminal windows works for two or three sessions, but it falls apart fast. You
need an <strong>orchestration layer</strong> - one place to start tasks, watch progress, and review diffs without juggling windows.</p>

<p>Codex and Claude both ship one. If you don’t want to be tied to a single provider, Conductor and Emdash are both good.
Try a couple, pick the one that fits how you actually work.</p>

<h2 id="its-a-skill-not-a-setting">It’s a skill, not a setting</h2>

<p>Working with AI well isn’t just about picking the right model or writing the perfect prompt. It’s about managing
yourself. The tools got faster, but your attention budget hasn’t changed.</p>

<p>If you don’t protect your focus, AI won’t just speed you up - it’ll speed up the chaos too.</p>]]></content><author><name></name></author><category term="ai" /><summary type="html"><![CDATA[AI made me faster, then it made me chaotic. Here's how I learned to run multiple agents without burning out.]]></summary></entry><entry><title type="html">Your website’s next visitor is an AI agent</title><link href="https://kukicola.io/posts/your-websites-next-visitor-is-an-ai-agent/" rel="alternate" type="text/html" title="Your website’s next visitor is an AI agent" /><published>2026-03-08T00:00:00+00:00</published><updated>2026-03-08T00:00:00+00:00</updated><id>https://kukicola.io/posts/your-websites-next-visitor-is-an-ai-agent</id><content type="html" xml:base="https://kukicola.io/posts/your-websites-next-visitor-is-an-ai-agent/"><![CDATA[<p>AI agents are your website’s new visitors. People are already using them to gather information,
perform research or even make purchases online. Whether we like it or not, it’s a new way to use the internet.
Agents do not care about modern design or fancy animations. They need an easy way to understand and interact with your content.
If your website isn’t ready for them, you’re already losing traffic you don’t even know about.
Let’s fix that.</p>

<h2 id="what-does-agent-friendly-even-mean">What does “agent-friendly” even mean?</h2>

<p>An agent-friendly website is one that AI agents can reliably navigate, understand, and interact with.
There’s a growing set of standards and conventions that make this possible. Some already exist and just need to be adopted. Others are brand new.</p>

<p>In this article, we’ll cover five building blocks - from controlling agent access with <code class="language-plaintext highlighter-rouge">robots.txt</code>, through helping them discover your content with <code class="language-plaintext highlighter-rouge">llms.txt</code> and markdown, to letting them interact with your product via OpenAPI and WebMCP.</p>

<h2 id="lets-start-simple---robotstxt">Let’s start simple - robots.txt</h2>

<p>You already have a <code class="language-plaintext highlighter-rouge">robots.txt</code>. But have you looked at it recently?</p>

<p>Traditionally, <code class="language-plaintext highlighter-rouge">robots.txt</code> controlled which crawlers can access your website.
It also applies to AI agents. Make sure that you’re not blocking them.</p>

<p>At this point, you may think - “hold on, I don’t want them to use my content for training!”.
It’s a valid point, but luckily, it’s possible to distinguish between an AI agent acting on behalf of a human and a crawler grabbing content for training.
For example, OpenAI provides <a href="https://developers.openai.com/api/docs/bots/">a list of user-agent strings they use</a>. Other providers like Anthropic and Google do the same.
So you may allow access for <code class="language-plaintext highlighter-rouge">OAI-SearchBot</code> and <code class="language-plaintext highlighter-rouge">ChatGPT-User</code> but block it for <code class="language-plaintext highlighter-rouge">GPTBot</code>.</p>

<p>Example <code class="language-plaintext highlighter-rouge">robots.txt</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User-Agent: *
Allow: /

User-agent: ChatGPT-User
Allow: /

User-agent: GPTBot
Disallow: /
</code></pre></div></div>

<h2 id="llmstxt---a-guide-for-ai-agents">llms.txt - a guide for AI agents</h2>

<p><code class="language-plaintext highlighter-rouge">robots.txt</code> tells agents what they <em>can</em> access. <code class="language-plaintext highlighter-rouge">llms.txt</code> tells them what they <em>should</em> access.</p>

<p>It’s a markdown file placed at the root of your website that provides an overview of your site.
Think of it as a README for AI agents - short description, links to key pages, and guidance on what matters.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># My SaaS Product</span>
<span class="gt">
&gt; A tool that helps developers ship faster.</span>

<span class="gu">## Docs</span>
<span class="p">
-</span> <span class="p">[</span><span class="nv">Getting Started</span><span class="p">](</span><span class="sx">/docs/getting-started</span><span class="p">)</span>
<span class="p">-</span> <span class="p">[</span><span class="nv">API Reference</span><span class="p">](</span><span class="sx">/docs/api</span><span class="p">)</span>
<span class="p">-</span> <span class="p">[</span><span class="nv">Changelog</span><span class="p">](</span><span class="sx">/changelog</span><span class="p">)</span>

<span class="gu">## Optional</span>
<span class="p">
-</span> <span class="p">[</span><span class="nv">Blog</span><span class="p">](</span><span class="sx">/blog</span><span class="p">)</span>
<span class="p">-</span> <span class="p">[</span><span class="nv">Pricing</span><span class="p">](</span><span class="sx">/pricing</span><span class="p">)</span>
</code></pre></div></div>

<p>Why markdown? Because it’s simple. No parsing, no noise. Just pure content that won’t eat thousands of tokens.
Some sites also provide an <code class="language-plaintext highlighter-rouge">llms-full.txt</code> - a more detailed version with full content inlined, so agents don’t even need to follow links.</p>

<h2 id="markdown-versions-of-your-content">Markdown versions of your content</h2>

<p><code class="language-plaintext highlighter-rouge">llms.txt</code> can point agents to specific pages, which ideally should also be available in markdown.
Providing markdown versions of your content is a great way to make sure agents can access it efficiently.</p>

<p>There are a few ways to do this - you can allow <code class="language-plaintext highlighter-rouge">.md</code> extension, a <code class="language-plaintext highlighter-rouge">?format=markdown</code> query param or just serve it via HTTP content negotiation (Accept header).</p>

<p>If you’re running a documentation site, a blog, or any content-heavy platform, this is low-hanging fruit.
Your content probably already exists in markdown before it gets rendered to HTML anyway.
Just make the source accessible and agents will love you for it.</p>

<h2 id="openapi---let-agents-use-your-product">OpenAPI - let agents use your product</h2>

<p>Everything we’ve covered so far is about agents <em>reading</em> your content. Let’s talk about <em>using</em> your product.</p>

<p>If your product has an API, an OpenAPI spec is the most important thing you can offer to AI agents.
It’s a standardized description of every endpoint, parameter, and response your API supports.</p>

<p>Agents can read an OpenAPI spec and immediately know how to interact with your product - no documentation crawling, no guessing, no hallucinated endpoints.</p>

<p>If you already have an OpenAPI spec, make sure it’s discoverable. Link to it from your <code class="language-plaintext highlighter-rouge">llms.txt</code> and your docs.</p>

<h2 id="webmcp---agent-native-integration">WebMCP - agent-native integration</h2>

<p>You’ve probably heard about MCP already, but in case you haven’t - it’s a standardized way to integrate AI agents with external services.
MCP servers expose <em>tools</em> (actions the agent can take), <em>resources</em> (data it can read), and <em>prompts</em> (predefined interactions).
Obviously, you can expose an MCP server just like an API.</p>

<p>WebMCP is a JavaScript interface. Wait, JavaScript? Didn’t we want to skip all HTML/CSS/JS noise and provide pure markdown?
Well, yes, but consider it as an alternative approach.
A lot of SPAs (which are terrible for agents) can be easily adjusted - you’ll just need to expose existing functions as MCP tools.
It can also create a hybrid experience, where a user and an agent cooperate.
Consider this example - you want to buy shoes. You’ll browse the catalog, find the ones you like, the agent can look for similar ones.
Then, you pick one pair, the agent fills the address and you confirm the payment.</p>

<p>WebMCP is still very fresh and experimental. At this time it’s available in Chrome’s early preview program.</p>

<h2 id="your-new-users-are-coming">Your new users are coming</h2>

<p>Great, now you know the key building blocks of agent-friendly websites. 
If you’d like to test if everything is in order on your website, take a look at <a href="https://agentprobe.io">AgentProbe</a>.
It’s a simple free tool that I built. It checks various aspects of your website and suggests improvements.</p>

<p>Keep an eye out, things are changing fast. 2026 is the year of AI agents, and we’re still in the early stages of their development.</p>]]></content><author><name></name></author><category term="ai" /><summary type="html"><![CDATA[AI agents are already browsing your website. Here's how to make sure they can understand and interact with it.]]></summary></entry><entry><title type="html">The review bottleneck: when AI codes faster than you can read</title><link href="https://kukicola.io/posts/the-review-bottleneck/" rel="alternate" type="text/html" title="The review bottleneck: when AI codes faster than you can read" /><published>2026-02-19T00:00:00+00:00</published><updated>2026-02-19T00:00:00+00:00</updated><id>https://kukicola.io/posts/the-review-bottleneck</id><content type="html" xml:base="https://kukicola.io/posts/the-review-bottleneck/"><![CDATA[<p>In just a few months, AI coding assistants went from autocompleting lines to shipping entire features in minutes.
Everyone who knows how to utilize AI can produce several times more code than before.
However, AI is not perfect and we, as humans, still need to review the code it produces.
Reviewing someone else’s code is not the most exciting part of the job - it’s just boring.
With thousands of lines of code, it’s easy to unconsciously skim through them and miss the important parts.
Let’s figure out how we can make the process less painful and time-consuming.</p>

<h2 id="the-review-problem">The review problem</h2>

<p>When writing code yourself, you have a mental model of what the code does.
Unfortunately, AI-generated code doesn’t give you that. A short summary of changes is all you get with a 500-line diff.
To properly review it, you need to understand the context, verify correctness, and catch all the subtle bugs.
Let’s face it - the same thing applies to your coworkers’ code, it’s not something new.
The problem begins when you have so much code to review that you can’t keep up with it.
Your review process becomes a bottleneck.</p>

<h2 id="dont-let-ai-repeat-its-mistakes">Don’t let AI repeat its mistakes</h2>

<p>What’s worse, your AI assistant won’t learn from its mistakes unless you make it do so.
Obviously, it’ll fix the issues you point out, but it’ll make them again in the future.
AI agents always start with a blank page. Their only persisted context is your code and memory files (AGENTS.md/CLAUDE.md).
If, during review, you notice that AI is not following specific patterns, code conventions, or just forgets to write tests, make sure to capture that.
Add instructions to your memory files or use dedicated Skills to avoid repeating the same mistakes.
You can also enforce rules by adding tools like linters to pre-commit hooks.
The goal is to reduce the number of style-related mistakes to zero, so you can focus on the important parts - what the code actually does.</p>

<h2 id="understanding-the-context">Understanding the context</h2>

<p>One of the biggest pain points in understanding the code is the organization of changes.
When reviewing a PR on GitHub, you’ll see all the changes grouped by file in alphabetical order.
If it’s a small PR, that’s fine, but when changes are spread across dozens of files and hundreds of lines of code,
you won’t be able to understand it quickly by going from top to bottom.
You’re left jumping between files, trying to piece together the story.
It takes a lot of time and effort to understand the big picture, and when you finally do, 
you still need to go through every file so you won’t miss anything.</p>

<h2 id="my-approach-let-ai-organize-the-review">My approach: let AI organize the review</h2>

<p>I’ve been experimenting with a different workflow. Since AI wrote the code, it might as well help me review it.
The idea is to let the assistant organize the review process. It can split the diff into logical units and add meaningful annotations.
Then I can review it in a more structured way.
Annotations help me understand the context of the change, making the whole thing less overwhelming.</p>

<p>Now the fun part - how to actually do it?</p>

<p>I built a <a href="https://github.com/kukicola/skills/tree/main/help-me-review">Claude Code skill</a> just for that.</p>

<p>Here’s what it does:</p>

<ol>
  <li><strong>Splits the diff into blocks</strong> - individual hunks, each representing one continuous change region (multiple changes in one file can result in multiple blocks)</li>
  <li><strong>Groups blocks by logical concern</strong> - not by file, but by what they actually do together. A “new API endpoint” section gathers the code in the route, controller, tests, and type definitions as one unit</li>
  <li><strong>Adds inline annotations</strong> - short explanations of <em>why</em> something changed, not what changed (you can read the diff, right?)</li>
  <li><strong>Generates an interactive HTML page</strong> - split-view diffs with syntax highlighting where you can click any line to leave comments, then export your feedback (UI included in the skill)</li>
</ol>

<p>After reviewing, I export my comments and feed them back into the agent so it can fix the issues.</p>

<p><img src="/assets/img/posts/ai-review/demo.png" alt="Demo" /></p>

<p>Feel free to try it out on your own code:</p>

<p>Install the skill:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx skills add kukicola/skills/help-me-review
</code></pre></div></div>

<p>Use in the agent:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/help-me-review [PR or branch or commit]
</code></pre></div></div>

<p>If you work on public repositories, you can also try out <a href="https://app.devin.ai/review">Devin Review</a>.</p>

<p>GitHub has also started <a href="https://github.blog/changelog/2025-10-28-grouping-changes-in-a-pull-request-with-copilot-in-public-preview/">experimenting with this</a> natively via Copilot, though only on paid plans.</p>

<h2 id="dont-let-it-become-ai-slop">Don’t let it become AI slop</h2>

<p>The developer role is shifting. Writing code is not the most time-consuming part of the job anymore.
As software engineers, we need to adapt - utilize AI to deliver value faster, at every step of the process.
Without proper orchestration and review, one may end up with so-called “AI slop” - huge technical debt, unmaintainable code, and security vulnerabilities.</p>]]></content><author><name></name></author><category term="ai" /><summary type="html"><![CDATA[AI can produce more code than ever. The bottleneck is no longer writing it - it's reviewing it. Here's how I made it less painful.]]></summary></entry><entry><title type="html">I’m Behind and I Don’t Care</title><link href="https://kukicola.io/posts/im-behind-and-i-dont-care/" rel="alternate" type="text/html" title="I’m Behind and I Don’t Care" /><published>2026-02-07T00:00:00+00:00</published><updated>2026-02-07T00:00:00+00:00</updated><id>https://kukicola.io/posts/im-behind-and-i-dont-care</id><content type="html" xml:base="https://kukicola.io/posts/im-behind-and-i-dont-care/"><![CDATA[<p>I woke up today and my workflow is already obsolete. At least that’s what X is telling me.
New models, new tools, new “game changing” workflows. Everything happens so fast in the AI world.
Social media is going crazy. You haven’t even tried the last big thing and it’s already obsolete.
It’s so easy to fall into the feeling of being behind.
This feeling may even transform into fear, since everyone shouts that AI is coming for your job.
So you try to catch up, check out the latest solutions, find something you like, spend hours perfecting your new workflow.
Then you wake up the next day and you’re behind again.</p>

<p>Yes, things are happening fast, but it’s not a reason to panic.
Think for a second - why did you become a developer? Because it was fun. It was a hobby, you enjoyed building things, you created something useful and it felt great.
Don’t let the constant hype keep you away from what you love and do best - building things. 
You can’t do that when you’re constantly improving your workflow because some guy on X codes “100x faster” thanks to “amazing new tool”.
It’s just another distraction. You need to find your own balance.</p>

<p>As a developer, I bet you encountered cases when you could make your code a bit better but it would require a big refactor
to get there. Sometimes it’s just not worth it. The same goes for your workflow. Tools come and go. The ones really worth using, stay. 
It’s like with frontend frameworks. There was a time when almost every day there was a new one. 
What happened? We still use React, Vue and Angular.
Nowadays, one week everyone is talking about Ralph Loop and on the next one OpenClaw takes all the spotlight.
Who knows what’s going to be on top tomorrow. It’s ok if you don’t test everything on your own.</p>

<p>I figured out my perfect workflow at the beginning of the year and so far I didn’t change it.
I got used to Claude Code. I feel confident using it, it feels right. 
So I don’t really care that according to some benchmarks GPT-5.3-Codex is a bit better.
I’m already moving faster than ever before. When I focus on building, everything else is just a distraction.</p>

<p>I’m not saying that you shouldn’t try new things. In the past, every time I started a new project I would try to use something new.
And I still do, I just don’t force it. I allow myself to be a bit behind, because I’m already way ahead of where I was.
I’m sure you heard of the Pareto Principle - 80% of the results come from 20% of the effort.
It applies to AI as well. I’m ok with the fact that my workflow is just 80% perfect.
The remaining 20% is not worth the constant chase. So yes, I’m behind. And that’s fine.</p>]]></content><author><name></name></author><category term="ai" /><summary type="html"><![CDATA[AI tools change every week. New models, new workflows, new hype. I decided to stop chasing and focus on building instead. Here's why being behind is not a bad thing.]]></summary></entry><entry><title type="html">AWS NAT Gateway cost is killing you? Enable IPv6 and Egress-only Internet Gateway!</title><link href="https://kukicola.io/posts/reducing-aws-nat-gateway-cost/" rel="alternate" type="text/html" title="AWS NAT Gateway cost is killing you? Enable IPv6 and Egress-only Internet Gateway!" /><published>2025-01-09T00:00:00+00:00</published><updated>2025-01-09T00:00:00+00:00</updated><id>https://kukicola.io/posts/reducing-aws-nat-gateway-cost</id><content type="html" xml:base="https://kukicola.io/posts/reducing-aws-nat-gateway-cost/"><![CDATA[<p>Sometimes I feel that AWS is the master of unexpected costs.
I was recently surprised by the cost of the NAT gateway - $0.045 per GB?! on top of $0.045/h?
Obviously you’ll need it if you want instances on private subnets to access the Internet.
For network-intensive applications such as web crawlers, a NAT gateway can be more expensive than instances.
Fortunately, there is a simple way to reduce the cost - enable IPv6 and use an Egress-only Internet gateway.</p>

<h2 id="egress-only-internet-gateway-vs-nat-gateway">Egress-only Internet Gateway vs NAT Gateway</h2>

<p>NAT Gateway allows instances on private subnets to access the Internet over IPv4.
Located on a public subnet, it connects instances to the Internet Gateway.</p>

<p><img src="/assets/img/posts/nat-gateway/nat.png" alt="Nat Gateway" /></p>

<p class="annotation">Source - https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat.html</p>

<p>Egress-only Internet Gateway allows instances on private subnets to access the Internet directly via IPv6.
Basically, you cut out the middleman, which isn’t necessary because IPv6 doesn’t require address translation.
What is important, your instances will still be inaccessible from the outside world.
And here’s the best part - it’s free!</p>

<p><img src="/assets/img/posts/nat-gateway/egress.png" alt="Nat Gateway" /></p>

<p class="annotation">Source - https://docs.aws.amazon.com/vpc/latest/userguide/egress-only-internet-gateway.html</p>

<p>Unfortunately, not all of the Internet is available on IPv6, so it’s not a silver bullet. We’ll keep NAT Gateways for IPv4 traffic.
This is what our final architecture will look like:</p>

<p><img src="/assets/img/posts/nat-gateway/final.png" alt="Final" /></p>

<p class="annotation">Source - https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6-example.html</p>

<h2 id="enabling-egress-only-internet-gateway">Enabling Egress-only Internet Gateway</h2>

<p>As you might guess, we need to enable IPv6 first.
This can be very easy if you are using the AWS CDK.
If you are doing a manual setup, you may need to go through some additional steps - see
<a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6-add.html">https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6-add.html</a></p>

<p>Note that you may need to update other parts of your infrastructure to support IPv6.
For example, if you’re using ECS, IPv6 will not work with the <code class="language-plaintext highlighter-rouge">bridge</code> network mode.</p>

<p>Also remember to update your security groups to prevent them from blocking outgoing traffic over IPv6.</p>

<p>With IPv6 enabled, you can create an Egress-only Internet Gateway.
AWS CDK created it automatically for me, but you can also create it manually - <a href="https://docs.aws.amazon.com/vpc/latest/userguide/egress-only-internet-gateway-working-with.html">https://docs.aws.amazon.com/vpc/latest/userguide/egress-only-internet-gateway-working-with.html</a></p>

<p>The easiest way to check if traffic is going over IPv6 is to check the NAT Gateway metrics in Cloudwatch.
You should see a significant drop in metrics such as <code class="language-plaintext highlighter-rouge">BytesOutToDestination</code> or <code class="language-plaintext highlighter-rouge">BytesInFromDestination</code>.</p>

<p>You may want to tweak your application to prioritize IPv6 traffic.
I can’t help you with that. In my case, I had to override DNS resolution to prioritize IPv6 over IPv4 for my HTTP client.</p>

<h2 id="other-ways-to-reduce-nat-gateway-cost">Other ways to reduce NAT Gateway cost</h2>

<p>There are a few other tips to reduce NAT gateway costs. I won’t cover them in detail.</p>

<ul>
  <li>Use Gateway Endpoints / Interface Endpoints for AWS services - <a href="https://docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html">https://docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html</a></li>
  <li>Launch your own NAT instance instead. It can be cheaper, but it requires more management overhead - <a href="https://docs.aws.amazon.com/vpc/latest/userguide/work-with-nat-instances.html">https://docs.aws.amazon.com/vpc/latest/userguide/work-with-nat-instances.html</a></li>
</ul>

<h2 id="summary">Summary</h2>

<p>If you are looking for a quick way to reduce the cost of NAT Gateway, enabling IPv6 and Egress-only Internet Gateway is an easy way to do it.
It’s not a silver bullet, but hopefully it will save you some money.</p>]]></content><author><name></name></author><category term="aws" /><category term="infrastructure" /><summary type="html"><![CDATA[Sometimes I feel that AWS is the master of unexpected costs. If you are looking for a quick way to reduce the cost of NAT Gateway, enabling IPv6 and Egress-only Internet Gateway is an easy way to do it.]]></summary></entry><entry><title type="html">My first Hanami app</title><link href="https://kukicola.io/posts/my-first-hanami-app/" rel="alternate" type="text/html" title="My first Hanami app" /><published>2023-02-14T00:00:00+00:00</published><updated>2023-02-14T00:00:00+00:00</updated><id>https://kukicola.io/posts/my-first-hanami-app</id><content type="html" xml:base="https://kukicola.io/posts/my-first-hanami-app/"><![CDATA[<h2 id="hanami-20">Hanami 2.0</h2>
<p>Hanami 2.0 was released in November 2022. 
It was the perfect timing for me, since at the time, I was planning to build a small side project.
I’ve never tried Hanami 1.x but read a lot about it, so when 2.0 was released I decided to give it a try.
It was such an amazing journey that I decided to share my opinion about the brand-new framework.</p>

<h2 id="about-the-project">About the project</h2>
<p>To provide some context let’s talk a bit about my project itself.</p>

<p>We use tons of open source gems everyday. Thanks to the hard work of their authors, we can build our apps faster.
I believe that we owe them some help. One of the ways to repay our debt, is to contribute to their software.
That’s where I had the idea for ShinyGems - a place, where all issues with “help wanted” tag, for the most popular gems, are gathered together. 
The app was pretty straightforward to build and consists of two parts:</p>
<ul>
  <li>background processing - periodically executed workers to pull data from RubyGems and GitHub</li>
  <li>web - pretty simple UI to display data we already have</li>
</ul>

<p>The app is already live, you can see it here: <a href="https://shinygems.dev">shinygems.dev</a>. <br />
Source code is available on GitHub: <a href="https://github.com/kukicola/shiny_gems">kukicola/shiny_gems</a></p>

<h2 id="first-impressions">First impressions</h2>
<p>Hanami handles a lot of things differently than Rails. The first thing that catches your eye is widely used dependency container.
In my opinion, dependency injection is an underrated pattern in the Ruby world 
(if you would like to learn more about DI, check out <a href="https://kukicola.io/posts/dependency-injection-in-ruby/">my article</a>).
Thanks to Hanami’s solution, we have clear, loosely coupled dependencies.</p>

<p>Another thing, that may be surprising at first, is that you won’t see any controllers. 
In Hanami, each action is a separate class with a <code class="language-plaintext highlighter-rouge">handle</code> method, which takes <code class="language-plaintext highlighter-rouge">request</code> and <code class="language-plaintext highlighter-rouge">response</code> arguments.
Out of the box we have parameter validation with type coercion. 
At first, I was afraid that it’ll lead me to a huge number of almost-empty classes but after creating few endpoints I started to notice the value of this approach.
Each action is extremely clean - we have dependencies defined at the top, params validation in the middle and finally the <code class="language-plaintext highlighter-rouge">handle</code> method fully focused on endpoints logic.
This approach solves one of the Rails problems - huge controllers with multiple actions and private methods, often used by only some of the endpoints.</p>

<p>Example:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">Web</span>
  <span class="k">module</span> <span class="nn">Actions</span>
    <span class="k">module</span> <span class="nn">Gems</span>
      <span class="k">class</span> <span class="nc">Index</span> <span class="o">&lt;</span> <span class="no">Web</span><span class="o">::</span><span class="no">Action</span>
        <span class="kp">include</span> <span class="no">Deps</span><span class="p">[</span><span class="s2">"repositories.gems_repository"</span><span class="p">]</span>

        <span class="n">before</span> <span class="ss">:validate_params!</span>

        <span class="no">DEFAULT_PARAMS</span> <span class="o">=</span> <span class="p">{</span>
          <span class="ss">page: </span><span class="mi">1</span><span class="p">,</span>
          <span class="ss">sort_by: </span><span class="s2">"downloads"</span>
        <span class="p">}.</span><span class="nf">freeze</span>

        <span class="no">SORTING_DIRECTIONS</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"name"</span><span class="p">,</span> <span class="s2">"stars"</span><span class="p">,</span> <span class="s2">"downloads"</span><span class="p">,</span> <span class="s2">"issues_count"</span><span class="p">,</span> <span class="s2">"recent_issues"</span><span class="p">].</span><span class="nf">freeze</span>

        <span class="n">params</span> <span class="k">do</span>
          <span class="n">optional</span><span class="p">(</span><span class="ss">:page</span><span class="p">).</span><span class="nf">filled</span><span class="p">(</span><span class="ss">:integer</span><span class="p">)</span>
          <span class="n">optional</span><span class="p">(</span><span class="ss">:sort_by</span><span class="p">).</span><span class="nf">filled</span><span class="p">(</span><span class="ss">:string</span><span class="p">,</span> <span class="ss">included_in?: </span><span class="no">SORTING_DIRECTIONS</span><span class="p">)</span>
        <span class="k">end</span>

        <span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span>
          <span class="n">params</span> <span class="o">=</span> <span class="no">DEFAULT_PARAMS</span><span class="p">.</span><span class="nf">merge</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="nf">params</span><span class="p">.</span><span class="nf">to_h</span><span class="p">)</span>

          <span class="n">result</span> <span class="o">=</span> <span class="n">gems_repository</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="ss">page: </span><span class="n">params</span><span class="p">[</span><span class="ss">:page</span><span class="p">],</span> <span class="ss">order: </span><span class="n">params</span><span class="p">[</span><span class="ss">:sort_by</span><span class="p">])</span>
          <span class="n">response</span><span class="p">[</span><span class="ss">:gems</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">.</span><span class="nf">to_a</span>
          <span class="n">response</span><span class="p">[</span><span class="ss">:pager</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">.</span><span class="nf">pager</span>
          <span class="n">response</span><span class="p">[</span><span class="ss">:sort_by</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="ss">:sort_by</span><span class="p">]</span>
        <span class="k">end</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Views are not included in 2.0 (will be included in 2.1) but I decided to use hanami/view directly from the main branch.
Since some concepts may change before the release I won’t dive deep into it. 
Let me just mention my two favorite things:</p>
<ul>
  <li>View is a class, not just a template. There is a place for view-related logic.</li>
  <li>Automatic object decoration (using classes called <code class="language-plaintext highlighter-rouge">parts</code>)</li>
</ul>

<p>I honestly can’t wait for the release.</p>

<h2 id="rom">ROM</h2>
<p>Persistent layer isn’t included in 2.0 as well but you can find instructions on how to integrate rom-rb
with hanami in <a href="https://guides.hanamirb.org/v2.0/introduction/getting-started/">getting started guide</a> (it’ll be built-in in 2.1).
As you can expect, it’s also different than Active Record.</p>

<p>The problem with models in Rails is that they tend to quickly become “master” objects containing huge amount of responsibilities.
Especially, they are responsible for both persistence and business logic.
ROM separates those layers. You’ll use repositories (on top of relations, mappers and commands) to communicate with the DB.
Instead of models, you’ll have entities - pure data in form of hash, struct or any custom object.</p>

<p>How many times have you seen long chains of Active Record methods scattered across controllers, services, etc.?
With repositories, you can extract it and fully focus on your business logic by working on plain data.
What is more, if we combine it with dependency injection, it’s easy to test things like services or actions without touching the database.</p>

<p>Sample repository:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">Processing</span>
  <span class="k">module</span> <span class="nn">Repositories</span>
    <span class="k">class</span> <span class="nc">GemsRepository</span> <span class="o">&lt;</span> <span class="no">ROM</span><span class="o">::</span><span class="no">Repository</span><span class="p">[</span><span class="ss">:gems</span><span class="p">]</span>
      <span class="kp">include</span> <span class="no">Deps</span><span class="p">[</span><span class="ss">container: </span><span class="s2">"persistence.rom"</span><span class="p">]</span>

      <span class="n">commands</span> <span class="ss">:create</span><span class="p">,</span> <span class="ss">update: :by_pk</span><span class="p">,</span> <span class="ss">delete: :by_pk</span>
      <span class="n">auto_struct</span> <span class="kp">true</span>

      <span class="k">def</span> <span class="nf">by_id</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="ss">with: </span><span class="kp">nil</span><span class="p">)</span>
        <span class="n">query</span> <span class="o">=</span> <span class="n">gems</span><span class="p">.</span><span class="nf">by_pk</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
        <span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="p">.</span><span class="nf">combine</span><span class="p">(</span><span class="n">with</span><span class="p">)</span> <span class="k">if</span> <span class="n">with</span>
        <span class="n">query</span><span class="p">.</span><span class="nf">one</span>
      <span class="k">end</span>

      <span class="k">def</span> <span class="nf">pluck_ids_for_hour</span><span class="p">(</span><span class="n">hour</span><span class="p">)</span>
        <span class="n">gems</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="no">Sequel</span><span class="p">.</span><span class="nf">lit</span><span class="p">(</span><span class="s2">"id % 24 = ?"</span><span class="p">,</span> <span class="n">hour</span><span class="p">)).</span><span class="nf">pluck</span><span class="p">(</span><span class="ss">:id</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="k">def</span> <span class="nf">pluck_name_by_list</span><span class="p">(</span><span class="n">items</span><span class="p">)</span>
        <span class="n">gems</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">name: </span><span class="n">items</span><span class="p">).</span><span class="nf">pluck</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="k">def</span> <span class="nf">replace_repo</span><span class="p">(</span><span class="n">old_id</span><span class="p">,</span> <span class="n">new_id</span><span class="p">)</span>
        <span class="n">gems</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">repo_id: </span><span class="n">old_id</span><span class="p">).</span><span class="nf">update</span><span class="p">(</span><span class="ss">repo_id: </span><span class="n">new_id</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>

</code></pre></div></div>

<p>ROM is a really huge topic, so if you’d like to learn more, take a look at <a href="https://rom-rb.org/learn/">official website</a>.</p>

<p>I have to admit I had a lot of problems with rom-factory (it’s like factory_bot for ROM) but I hope it’ll get better in the future.</p>

<h2 id="slices">Slices</h2>
<p>It’s time for my favorite part - Slices. They allow you to split your application into smaller parts/modules.
For example, you can split it by features and keep the directory structure based on them, not class type 
(<code class="language-plaintext highlighter-rouge">feature/[actions/services/etc]/some_class.rb</code> instead of <code class="language-plaintext highlighter-rouge">[actions/services/etc]/feature/some_class.rb</code>).
The closest Rails solution, that I could compare it to, would be engines.</p>

<p>Each slice has a separate dependency container, you can define which classes should be exposed outside the slice.
When used properly they can help you keep your code organized and isolated.</p>

<p>What is more, you can define which slices should be loaded using an environment variable.
In ShinyGems, I have two slices - “web” and “processing”.
“Processing” is loaded in sidekiq process. It contains all the workers and gems required to pull data from APIs.
“Web”, as the name suggests, is loaded in web process. It contains all my actions and views. 
I don’t need workers or gems like <code class="language-plaintext highlighter-rouge">octokit</code> here so, thanks to slices, they are not loaded, keeping the memory usage low.</p>

<p>Directory tree of ShinyGems slices:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>slices
├── processing
│   ├── config
│   ├── repositories
│   ├── services
│   └── workers
└── web
    ├── actions
    ├── assets
    ├── lib
    ├── repositories
    ├── services
    ├── templates
    └── views
</code></pre></div></div>

<h2 id="compared-to-rails">Compared to Rails</h2>
<p>I hope you don’t expect me to answer the question if Hanami is better than Rails.
As always - it depends. It’s different. 
You won’t be able to build apps in Hanami as fast as in Rails.
Although, Hanami encourages you to write cleaner and easier-to-test code,
which will be painless to maintain.</p>

<h2 id="a-breath-of-fresh-air">A breath of fresh air</h2>
<p>In Hanami guides, you can see that is built for maintainable, secure, faster and testable Ruby applications.
Looks like the authors did their job perfectly:</p>
<ul>
  <li>maintainable - slices, no fat models or controllers - check!</li>
  <li>secure - CSRF protection, CSP, parameters validations etc. out of the box - check!</li>
  <li>faster - it’s blazingly fast (for example, ShinyGems homepage response takes 10-15ms) - check!</li>
  <li>testable - separation between DB and application layers, DI - check!</li>
</ul>

<p>I really enjoyed building ShinyGems with Hanami. Even with some hiccups, I felt like I’m learning something new every day.
I would recommend you to try it even if you’re strongly attached to Rails.
It’s always worth to see different approaches, gain fresh perspective.</p>

<p>If you’ll like to take a look at the real-world Hanami app I remind you that
<a href="https://shinygems.dev">ShinyGems</a> is open source: <a href="https://github.com/kukicola/shiny_gems">kukicola/shiny_gems</a>.</p>]]></content><author><name></name></author><category term="ruby" /><category term="hanami" /><summary type="html"><![CDATA[In my opinion, Hanami is a breath of fresh air in the ruby world. Let's take a look at why, and how it's different from Rails.]]></summary></entry><entry><title type="html">Signed URLs with Ruby</title><link href="https://kukicola.io/posts/signed-urls-with-ruby/" rel="alternate" type="text/html" title="Signed URLs with Ruby" /><published>2023-01-16T00:00:00+00:00</published><updated>2023-01-16T00:00:00+00:00</updated><id>https://kukicola.io/posts/signed-urls-with-ruby</id><content type="html" xml:base="https://kukicola.io/posts/signed-urls-with-ruby/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Signed URLs can be a very useful solution in many cases when you need to provide limited access to some resources or actions.
Today I’ll focus on when and how to use them in Ruby, with Rails, or by providing a custom implementation.</p>

<h2 id="about-signed-urls">About Signed URLs</h2>
<p>Signed URLs, as the name suggests, contain signatures that allow us to validate if they were generated by a trusted source.
What is more, they may expire over time.</p>

<p>They can be used in many cases:</p>
<ul>
  <li>account confirmations, password change confirmations, etc. without storing any tokens in DB</li>
  <li>providing access to resources for not authenticated users (for example, users in the app can generate some reports and share them with anyone with a link)</li>
  <li>providing access to resources in other apps without shared authentication (example: S3 direct upload) - in this case both services need to use the same secret to sign and verify URLs. What is important, your app doesn’t need to make any calls to API to generate such URLs.</li>
</ul>

<h2 id="how-it-works">How it works?</h2>
<p>Signed URL apart from a standard query usually contains at least two additional params - <code class="language-plaintext highlighter-rouge">signature</code> and <code class="language-plaintext highlighter-rouge">expires_at</code>.
To generate such URL we have to calculate the signature using the rest of the params.</p>

<p>Example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/reports/50?signature=a6450e8d5049f511930f18c6d897adc31085453cf5bb8e246f35ab0109464499&amp;expires_at=1673620751
</code></pre></div></div>

<p>Signature is calculated based on resource type - <code class="language-plaintext highlighter-rouge">reports</code>, id - <code class="language-plaintext highlighter-rouge">50</code>, and expiry time - <code class="language-plaintext highlighter-rouge">1673620751</code>.</p>

<p>To validate if the URL is valid we generate the signature again and compare it with the one in params.</p>

<p>In another approach (for example in the one implemented in Rails) you can merge all these things into one token.
Example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/reports/share/BAhJIhpyZXBvcnRzLTUwLTE2NzM2MjA5MjAGOgZFVA==--41083ebf51767fb089f0fbaac5b4a6c46638c51e
</code></pre></div></div>

<p>Th first part of this token (before <code class="language-plaintext highlighter-rouge">--</code>) contains information about resource and expiry time:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Marshal</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="no">Base64</span><span class="p">.</span><span class="nf">decode64</span><span class="p">(</span><span class="s1">'BAhJIhpyZXBvcnRzLTUwLTE2NzM2MjA5MjAGOgZFVA=='</span><span class="p">))</span>
<span class="o">=&gt;</span> <span class="s2">"reports-50-1673620920"</span>
</code></pre></div></div>

<p>The second part is just a signature.</p>

<p>Now let’s see how can we generate and validate such URLs in ruby.</p>

<h2 id="rails-signed-id">Rails Signed ID</h2>
<p>If you are using Rails and need to generate a signed URL for one of your models, the easiest way is to use Signed ID (introduced in 6.1).</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">signed_id</span> <span class="o">=</span> <span class="no">Report</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="mi">50</span><span class="p">).</span><span class="nf">signed_id</span><span class="p">(</span><span class="ss">expires_in: </span><span class="mi">3</span><span class="p">.</span><span class="nf">hours</span><span class="p">)</span>
<span class="n">url</span> <span class="o">=</span> <span class="s2">"/reports/share/</span><span class="si">#{</span><span class="n">signed_id</span><span class="si">}</span><span class="s2">"</span>
</code></pre></div></div>

<p>To find a resource and validate the signature:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Report</span><span class="p">.</span><span class="nf">find_signed</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:signed_id</span><span class="p">])</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;Report id: 50... </span>
<span class="c1"># now we can allow user to view report</span>

<span class="no">Report</span><span class="p">.</span><span class="nf">find_signed</span><span class="p">(</span><span class="s2">"some-invalid-string"</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="c1"># signature is invalid, don't allow user to see the report</span>
</code></pre></div></div>

<p>You can also pass <code class="language-plaintext highlighter-rouge">purpose</code> to <code class="language-plaintext highlighter-rouge">signed_id</code> method if you generate signed URLs for different actions on your model (for example <code class="language-plaintext highlighter-rouge">password_reset</code> and <code class="language-plaintext highlighter-rouge">account_confirmation</code> on <code class="language-plaintext highlighter-rouge">User</code>).</p>

<h2 id="activesupportmessageverifier">ActiveSupport::MessageVerifier</h2>
<p>Another approach in Rails (or any other app using ActiveSupport) is MessageVerifier. It’s useful if your resource is not a model or you are not using ActiveRecord.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">verifier</span> <span class="o">=</span> <span class="no">ActiveSupport</span><span class="o">::</span><span class="no">MessageVerifier</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">ENV</span><span class="p">[</span><span class="s1">'MY_SECRET_KEY'</span><span class="p">])</span>
<span class="n">signed_msg</span> <span class="o">=</span> <span class="n">verifier</span><span class="p">.</span><span class="nf">generate</span><span class="p">(</span><span class="s2">"reports-50"</span><span class="p">,</span> <span class="ss">expires_in: </span><span class="mi">3</span><span class="p">.</span><span class="nf">hours</span><span class="p">)</span>
<span class="n">url</span> <span class="o">=</span> <span class="s2">"/reports/share/</span><span class="si">#{</span><span class="n">signed_msg</span><span class="si">}</span><span class="s2">"</span>
</code></pre></div></div>

<p>Signature validation:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">verifier</span><span class="p">.</span><span class="nf">verified</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:signed_msg</span><span class="p">])</span>
<span class="o">=&gt;</span> <span class="s2">"reports-50"</span>

<span class="n">verifier</span><span class="p">.</span><span class="nf">verified</span><span class="p">(</span><span class="s2">"some-invalid-string"</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>

<span class="n">verifier</span><span class="p">.</span><span class="nf">verify</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:signed_msg</span><span class="p">])</span>
<span class="o">=&gt;</span> <span class="s2">"reports-50"</span>

<span class="n">verifier</span><span class="p">.</span><span class="nf">verify</span><span class="p">(</span><span class="s2">"some-invalid-string"</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="no">ActiveSupport</span><span class="o">::</span><span class="no">MessageVerifier</span><span class="o">::</span><span class="no">InvalidSignature</span>
</code></pre></div></div>

<h2 id="from-the-scratch">From the scratch</h2>
<p>If you are not using ActiveSupport or for some reason you have to implement it from scratch it’s pretty easy. 
To keep it simple let’s implement a case when <code class="language-plaintext highlighter-rouge">signature</code> is a separate param from resource id and <code class="language-plaintext highlighter-rouge">expires_at</code>
(<code class="language-plaintext highlighter-rouge">/reports/50?signature=...&amp;expires_at=...</code>).</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MessageSigner</span>
  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">key</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'MY_SECRET_KEY'</span><span class="p">])</span>
    <span class="vi">@key</span> <span class="o">=</span> <span class="n">key</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">sign</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">expires_at</span><span class="p">:)</span>
    <span class="no">OpenSSL</span><span class="o">::</span><span class="no">HMAC</span><span class="p">.</span><span class="nf">hexdigest</span><span class="p">(</span><span class="s1">'SHA256'</span><span class="p">,</span> <span class="vi">@key</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">message</span><span class="si">}</span><span class="s2">--</span><span class="si">#{</span><span class="n">expires_at</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># calculate signature</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">verify</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">signature</span><span class="p">,</span> <span class="n">expires_at</span><span class="p">:)</span>
    <span class="c1"># check if signature is still valid, </span>
    <span class="c1"># you can trust expires_at params since if it was modified by user it'll fail on signature validation</span>
    <span class="k">return</span> <span class="kp">false</span> <span class="k">if</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">.</span><span class="nf">to_i</span> <span class="o">&gt;=</span> <span class="n">expires_at</span>

    <span class="n">expected_signature</span> <span class="o">=</span> <span class="n">sign</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">expires_at: </span><span class="n">expires_at</span><span class="p">)</span> <span class="c1"># recalculate signature</span>
    <span class="no">Rack</span><span class="o">::</span><span class="no">Utils</span><span class="p">.</span><span class="nf">secure_compare</span><span class="p">(</span><span class="n">signature</span><span class="p">,</span> <span class="n">expected_signature</span><span class="p">)</span> <span class="c1"># use secure_compare to avoid timing attacks</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Creating signature:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">signer</span> <span class="o">=</span> <span class="no">MessageSigner</span><span class="p">.</span><span class="nf">new</span>
<span class="n">expires_at</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">.</span><span class="nf">to_i</span> <span class="o">+</span> <span class="mi">60</span><span class="o">*</span><span class="mi">60</span><span class="o">*</span><span class="mi">3</span>
<span class="n">signature</span> <span class="o">=</span> <span class="n">signer</span><span class="p">.</span><span class="nf">sign</span><span class="p">(</span><span class="s2">"reports-50"</span><span class="p">,</span> <span class="ss">expires_at: </span><span class="n">expires_at</span><span class="p">)</span>
<span class="n">url</span> <span class="o">=</span> <span class="s2">"/reports/50?signature=</span><span class="si">#{</span><span class="n">signature</span><span class="si">}</span><span class="s2">&amp;expires_at=</span><span class="si">#{</span><span class="n">expires_at</span><span class="si">}</span><span class="s2">"</span>
</code></pre></div></div>

<p>Validating signature:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">signer</span> <span class="o">=</span> <span class="no">MessageSigner</span><span class="p">.</span><span class="nf">new</span>
<span class="n">signer</span><span class="p">.</span><span class="nf">verify</span><span class="p">(</span><span class="s2">"reports-</span><span class="si">#{</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="ss">:signature</span><span class="p">],</span> <span class="ss">expires_at: </span><span class="n">params</span><span class="p">[</span><span class="ss">:expires_at</span><span class="p">].</span><span class="nf">to_i</span><span class="p">)</span>
<span class="c1"># allow user to see report if verify method returns true</span>
</code></pre></div></div>

<p>To implement behavior like in Rails all you have to do is merge <code class="language-plaintext highlighter-rouge">message</code> and <code class="language-plaintext highlighter-rouge">expires_at</code> (manually to one string or with some serializer like Marshal)
and encode it with Base64. You can consider it as your homework :)</p>

<h2 id="summary">Summary</h2>
<p>As you can see generating and validating signed URLs in Ruby is really simple with or without Rails. 
It can be used for many purposes as an alternative to other solutions (temporary tokens in DB - ugh!).</p>]]></content><author><name></name></author><category term="ruby" /><category term="rails" /><category term="security" /><summary type="html"><![CDATA[Signed URLs can be a very useful solution in many cases when you need to provide limited access to some resources or actions. As the name suggests, signed URLs contain signatures that allow us to validate if they were generated by a trusted source. I'll focus on when and how to use them in Ruby, with Rails, or by providing a custom implementation.]]></summary></entry><entry><title type="html">Securing Rails applications with Content Security Policy</title><link href="https://kukicola.io/posts/securing-rails-app-with-csp/" rel="alternate" type="text/html" title="Securing Rails applications with Content Security Policy" /><published>2022-10-27T00:00:00+00:00</published><updated>2022-10-27T00:00:00+00:00</updated><id>https://kukicola.io/posts/securing-rails-app-with-csp</id><content type="html" xml:base="https://kukicola.io/posts/securing-rails-app-with-csp/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Nowadays web application security is a crucial and unfortunately sometimes a bit neglected matter.
Today, I’ll focus on Content Security Policy - a handy mechanism that can protect our app from XSS attacks.
It’s not Rails-specific, it can (or even should) be implemented in every web application
but Rails provides great helpers to make implementation even easier.</p>

<h2 id="xss-attacks">XSS attacks</h2>
<p>XSS (Cross-site scripting) is probably one of the most common vulnerabilities in web applications.
If our application is vulnerable, an attacker can inject malicious code into the victim’s browser,
what can lead to many dangerous situations like, for example, session hijacking.</p>

<p>Let’s take a simple example - we have a blog with comments. The attacker creates a new comment with the following content:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Great article! <span class="nt">&lt;script&gt;</span><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hacked!</span><span class="dl">'</span><span class="p">)</span><span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>If, for some reason, we won’t sanitize it while displaying the script will be executed in the browser of our visitors.
By default, ERB keeps us safe and escapes HTML, so code:</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;%=</span> <span class="s1">'abc &lt;script&gt;alert("hi!")&lt;/script&gt;'</span> <span class="cp">%&gt;</span>
</code></pre></div></div>
<p>Will be rendered as plain text, <code class="language-plaintext highlighter-rouge">&lt;</code> will be replaced with <code class="language-plaintext highlighter-rouge">&amp;amp;lt;</code>.
Unfortunately, there are some cases when it’s not that easy:</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;%=</span><span class="o">=</span> <span class="s2">"&lt;b&gt;</span><span class="si">#{</span><span class="n">comment</span><span class="p">.</span><span class="nf">username</span><span class="si">}</span><span class="s2">&lt;/b&gt;: </span><span class="si">#{</span><span class="n">comment</span><span class="p">.</span><span class="nf">content</span><span class="si">}</span><span class="s2">"</span> <span class="cp">%&gt;</span>
</code></pre></div></div>

<p>Here, some careless developer wanted to display the username bolded, did it in a pretty bad way, and as a result created a vulnerability!
Both <code class="language-plaintext highlighter-rouge">comment.username</code> and <code class="language-plaintext highlighter-rouge">comment.content</code> aren’t escaped, because of <code class="language-plaintext highlighter-rouge">&lt;%==</code> which was added to avoid escaping <code class="language-plaintext highlighter-rouge">&lt;b&gt;</code>.
In this code, it’s pretty obvious but unfortunately, in many cases, it’s not.</p>

<h2 id="content-security-policy-csp">Content Security Policy (CSP)</h2>
<p>There are many ways to prevent XSS or reduce its impact but CSP is a very simple to implement mechanism that eliminates
most of the vulnerabilities right away. Rails provides helpers which make implementation even easier.</p>

<p>CSP allows us to specify trusted sources for all external resources like images or scripts.
Adding such resources from untrusted sources will result in blocking them by the browser.</p>

<p>In the newly created Rails app, we have a <code class="language-plaintext highlighter-rouge">config/content_security_policy.rb</code> file with basic configuration.
It’s disabled by default but all we have to do is to uncomment the code in the file.
In version 7.0.4 it will look like this (after uncommenting):</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">configure</span> <span class="k">do</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">content_security_policy</span> <span class="k">do</span> <span class="o">|</span><span class="n">policy</span><span class="o">|</span>
    <span class="n">policy</span><span class="p">.</span><span class="nf">default_src</span> <span class="ss">:self</span><span class="p">,</span> <span class="ss">:https</span>
    <span class="n">policy</span><span class="p">.</span><span class="nf">font_src</span>    <span class="ss">:self</span><span class="p">,</span> <span class="ss">:https</span><span class="p">,</span> <span class="ss">:data</span>
    <span class="n">policy</span><span class="p">.</span><span class="nf">img_src</span>     <span class="ss">:self</span><span class="p">,</span> <span class="ss">:https</span><span class="p">,</span> <span class="ss">:data</span>
    <span class="n">policy</span><span class="p">.</span><span class="nf">object_src</span>  <span class="ss">:none</span>
    <span class="n">policy</span><span class="p">.</span><span class="nf">script_src</span>  <span class="ss">:self</span><span class="p">,</span> <span class="ss">:https</span>
    <span class="n">policy</span><span class="p">.</span><span class="nf">style_src</span>   <span class="ss">:self</span><span class="p">,</span> <span class="ss">:https</span>
    <span class="c1"># Specify URI for violation reports</span>
    <span class="c1"># policy.report_uri "/csp-violation-report-endpoint"</span>
  <span class="k">end</span>

  <span class="c1"># Generate session nonces for permitted importmap and inline scripts</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">content_security_policy_nonce_generator</span> <span class="o">=</span> <span class="o">-&gt;</span><span class="p">(</span><span class="n">request</span><span class="p">)</span> <span class="p">{</span> <span class="n">request</span><span class="p">.</span><span class="nf">session</span><span class="p">.</span><span class="nf">id</span><span class="p">.</span><span class="nf">to_s</span> <span class="p">}</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">content_security_policy_nonce_directives</span> <span class="o">=</span> <span class="sx">%w(script-src)</span>

  <span class="c1"># Report violations without enforcing the policy.</span>
  <span class="c1"># config.content_security_policy_report_only = true</span>
<span class="k">end</span>
</code></pre></div></div>

<p>From now, our app will add a following header to the response:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Content-Security-Policy: default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src 'self' https: 'nonce-26ea5aaa858b26e451c1d9209e031f0a'; style-src 'self' https:
</code></pre></div></div>

<p>Let’s take a closer look at what it does. We have a list of different types of resources and their trusted sources.</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">:self</code> - allows resources from current origin - so if your page is under <code class="language-plaintext highlighter-rouge">somedomain.com</code> it will allow all resources within this domain.</li>
  <li><code class="language-plaintext highlighter-rouge">:https</code> - it will allow loading resources from any origin as long as it’s using HTTPS (HTTP requests will be blocked)</li>
  <li><code class="language-plaintext highlighter-rouge">:data</code> - data URIs (for example: <code class="language-plaintext highlighter-rouge">data:image/gif;base64,R0lGODlhEAAQA...</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">:none</code> - don’t allow loading objects from any source</li>
</ul>

<p>So looking at our config it will allow resources except for the <code class="language-plaintext highlighter-rouge">object</code> type (<code class="language-plaintext highlighter-rouge">&lt;object&gt;</code>, <code class="language-plaintext highlighter-rouge">&lt;embed&gt;</code>, and <code class="language-plaintext highlighter-rouge">&lt;applet&gt;</code>) to be loaded from our domain, HTTPS URLs, and Data URIs.
As you can see it’s easy to customize it per resource type. All types that are not present in the CSP header will fall back to <code class="language-plaintext highlighter-rouge">default_src</code>.
You can check the full list of supported directives <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#directives">here</a>.</p>

<p>We’ll take a look at the rest of the config later. Let’s focus on <code class="language-plaintext highlighter-rouge">script-src</code> for now, since it’s the most important one when talking about XSS.
Apart from blocking scripts from the insecure connections, it will block the following things:</p>
<ul>
  <li>inline <code class="language-plaintext highlighter-rouge">&lt;script&gt;</code> blocks</li>
  <li>javascript in HTML attributes like <code class="language-plaintext highlighter-rouge">onclick="doSomething()""</code></li>
  <li><code class="language-plaintext highlighter-rouge">eval</code> and similar javascript methods</li>
</ul>

<p>Thanks to that the code from the previous example will be blocked, cool, right?
These are pretty solid settings for the start but can be improved.
The attacker can still inject code like <code class="language-plaintext highlighter-rouge">&lt;script src="https://my.evil.site.com/dirty-script.js"&gt;&lt;/script&gt;</code>.</p>

<h2 id="improving-script-src-directive">Improving script-src directive</h2>
<p>To minimalize the risk of vulnerabilities we can remove <code class="language-plaintext highlighter-rouge">:https</code> from <code class="language-plaintext highlighter-rouge">script_src</code> and provide a list of allowed domains instead.
It may take some time, especially if you are using stuff like Google Analytics, Facebook pixels, etc.
Keep in mind that subdomains are not included by default but you can use wildcards like <code class="language-plaintext highlighter-rouge">'*.google-analytics.com'</code>.</p>

<p>Blocked inline scripts may be a problem, sometimes we would like to use them for various reasons.
We could use <code class="language-plaintext highlighter-rouge">:unsafe_inline</code> to allow them but it would significantly impact our security and to be honest make our policy pointless.
Luckily, there is a better way to do this.</p>

<h2 id="nonce">Nonce</h2>
<p>If you take another look at the generated header you’ll see the following content in the <code class="language-plaintext highlighter-rouge">script-src</code> part:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>'nonce-26ea5aaa858b26e451c1d9209e031f0a'
</code></pre></div></div>

<p>It tells the browser to accept inline script with the following nonce value:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">nonce=</span><span class="s">"26ea5aaa858b26e451c1d9209e031f0a"</span><span class="nt">&gt;</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello</span><span class="dl">'</span><span class="p">)</span>
  <span class="c1">// script will be executed because it has correct noonce value</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>To keep it safe <code class="language-plaintext highlighter-rouge">nonce</code> should be random (so the attacker won’t be able to guess it).
By default, Rails uses session id as a nonce but I recommend changing it.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">config</span><span class="p">.</span><span class="nf">content_security_policy_nonce_generator</span> <span class="o">=</span> <span class="o">-&gt;</span><span class="p">(</span><span class="n">_request</span><span class="p">)</span> <span class="p">{</span> <span class="no">SecureRandom</span><span class="p">.</span><span class="nf">base64</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span> <span class="p">}</span>
</code></pre></div></div>

<p>Now nonce will be different on each request making it even safer.
Using session id has some advantages - it can be useful if you are using <a href="https://edgeguides.rubyonrails.org/caching_with_rails.html#conditional-get-caching">Conditional GET caching</a> (random noonce will prevent pages from being cached)
but in most cases keeping it random is the best way to go.</p>

<p>To use it for your inline script just add <code class="language-plaintext highlighter-rouge">nonce: true</code> to the <code class="language-plaintext highlighter-rouge">javascript_tag</code> helper:</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;%=</span> <span class="n">javascript_tag</span><span class="p">(</span><span class="ss">nonce: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="cp">%&gt;</span>
  console.log('hello')
<span class="cp">&lt;%</span> <span class="k">end</span> <span class="cp">%&gt;</span>
</code></pre></div></div>

<h2 id="adding-csp-to-existing-application">Adding CSP to existing application</h2>
<p>Adding CSP to an existing application can be painful, especially if it’s a large app with a lot of javascript.
To do that without breaking anything we can use reporting feature.</p>

<p>First, let’s uncomment the following line:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">policy</span><span class="p">.</span><span class="nf">report_uri</span> <span class="s2">"/csp-violation-report-endpoint"</span>
</code></pre></div></div>

<p>It orders the browser to send policy violation reports to <code class="language-plaintext highlighter-rouge">/csp-violation-report-endpoint</code>.
You’ll have to implement such endpoint and store reports somewhere - in DB or anywhere else.
The browser will send POST requests with a simple JSON body. It will include information about which rule was violated
as well as blocked resource URLs.</p>

<p>Keeping it like that will still result in blocking such resources but we can change that as well, by uncommenting:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">config</span><span class="p">.</span><span class="nf">content_security_policy_report_only</span> <span class="o">=</span> <span class="kp">true</span>
</code></pre></div></div>

<p>Now, we will receive notifications about violations but they won’t be blocked.</p>

<p>Thanks to that we can easily integrate CSP into existing apps.
First we setup our policy in report-only mode, we gather reports, fix our policy (by adding missing URLs) or our code (by adding nonce to inline scripts)
and finally, we can turn off report-only mode.</p>

<p>It’s worth mentioning that sometimes you’ll receive weird violation reports not really related to your app -
they are the results of different browser add-ons or extensions, you can safely ignore them.</p>

<h2 id="summary">Summary</h2>
<p>So to summarize - CSP is a great mechanism that can improve the security of your app with relatively simple implementation.
It can block most of the potential XSS attacks by disabling the execution of scripts from untrusted sources.
Although, you should still sanitize/escape user inputs since it doesn’t protect us from injecting HTML.</p>

<p>If you’ll like to know all CSP directives and features please take a look at <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy">MDN</a>.</p>

<p>Let me know if you’ll like to see more security-related articles!</p>]]></content><author><name></name></author><category term="ruby" /><category term="rails" /><category term="security" /><summary type="html"><![CDATA[Nowadays web application security is a crucial and unfortunately sometimes a bit neglected matter. Today, I'll focus on Content Security Policy - a handy mechanism that can protect our app from XSS attacks.]]></summary></entry><entry><title type="html">Improve your specs quality with branch coverage</title><link href="https://kukicola.io/posts/improve-your-specs-quality-with-branch-coverage/" rel="alternate" type="text/html" title="Improve your specs quality with branch coverage" /><published>2022-04-29T00:00:00+00:00</published><updated>2022-04-29T00:00:00+00:00</updated><id>https://kukicola.io/posts/improve-your-specs-quality-with-branch-coverage</id><content type="html" xml:base="https://kukicola.io/posts/improve-your-specs-quality-with-branch-coverage/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>It’s a common practice to measure the quality of tests to make sure they cover all the code.
Most ruby developers are familiar with SimpleCov.
By default, it measures only line coverage, which sometimes can make false assurance that our code is fully tested.
In Ruby we have many options to write conditional code in single lines:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">return</span> <span class="k">if</span> <span class="n">something_happened?</span>
</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">some_var</span> <span class="o">=</span> <span class="n">argument</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">SomeClass</span><span class="p">)</span> <span class="p">?</span> <span class="n">argument</span> <span class="p">:</span> <span class="no">SomeClass</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">argument</span><span class="p">)</span>
</code></pre></div></div>
<p>In such cases, line coverage will mark lines as covered no matter what’s the result of the condition.</p>

<h2 id="line-coverage">Line coverage</h2>
<p>Let’s take a look at a very simple example:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">read_file_if_exists</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
  <span class="k">return</span> <span class="s1">''</span> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">exist?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
  
  <span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>and spec for it:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s1">'simplecov'</span>

<span class="no">SimpleCov</span><span class="p">.</span><span class="nf">start</span>

<span class="nb">require_relative</span> <span class="s1">'./example.rb'</span>

<span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="s1">'read_file_if_exists'</span> <span class="k">do</span>
  <span class="n">subject</span> <span class="p">{</span> <span class="n">read_file_if_exists</span><span class="p">(</span><span class="s1">'example.txt'</span><span class="p">)</span> <span class="p">}</span>

  <span class="n">it</span> <span class="s1">'returns content of the file'</span> <span class="k">do</span>
    <span class="n">expect</span><span class="p">(</span><span class="n">subject</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s1">'abc'</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>As you’ve probably noticed I haven’t tested the case when a file doesn’t exist.
Yet my line coverage is 100%.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rspec example_spec.rb
.

Finished in 0.0014 seconds (files took 0.07227 seconds to load)
1 example, 0 failures

Coverage report generated for RSpec to /Users/kukicola/Desktop/example/coverage. 3 / 3 LOC (100.0%) covered.
</code></pre></div></div>

<p>My test isn’t perfect but I think we can agree that in this case, it’s not the end of the world.</p>

<p>Let’s move on to the second example:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">number_to_dollar</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
    <span class="n">dollar_part</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">number</span><span class="p">.</span><span class="nf">to_i</span><span class="si">}</span><span class="s2"> dollar(s)"</span>
    <span class="n">cent_part</span> <span class="o">=</span> <span class="n">number</span> <span class="o">%</span> <span class="mi">1</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">?</span> <span class="s2">" </span><span class="si">#{</span><span class="p">((</span><span class="n">number</span> <span class="o">-</span> <span class="n">number</span><span class="p">.</span><span class="nf">to_i</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span><span class="p">).</span><span class="nf">to_i</span><span class="si">}</span><span class="s2"> cent(s)"</span> <span class="p">:</span> <span class="kp">nil</span>
    <span class="n">dollar_part</span> <span class="o">+</span> <span class="n">cent_part</span>
<span class="k">end</span>
</code></pre></div></div>
<p>and spec for it:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s1">'simplecov'</span>

<span class="no">SimpleCov</span><span class="p">.</span><span class="nf">start</span>

<span class="nb">require_relative</span> <span class="s1">'./example2.rb'</span>

<span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="s1">'number_to_dollar'</span> <span class="k">do</span>
    <span class="n">subject</span> <span class="p">{</span> <span class="n">number_to_dollar</span><span class="p">(</span><span class="mf">2.56</span><span class="p">)</span> <span class="p">}</span>

    <span class="n">it</span> <span class="s1">'returns dollar and cents'</span> <span class="k">do</span>
        <span class="n">expect</span><span class="p">(</span><span class="n">subject</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s1">'2 dollar(s) 56 cent(s)'</span><span class="p">)</span>
    <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>My test will pass and line coverage is 100%.
If you look carefully you’ll see that my code has an obvious bug.
For values without a decimal part it will raise an error because it won’t be able to add <code class="language-plaintext highlighter-rouge">nil</code> to the string:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>irb(main):002:0&gt; number_to_dollar(2)
/Users/kukicola/Desktop/example/example2.rb:4:in `+': no implicit conversion of nil into String (TypeError)
</code></pre></div></div>

<h2 id="what-is-branch-coverage-and-why-its-important">What is branch coverage and why it’s important?</h2>
<p>Branch coverage is a measure of how many branches/results of the conditions have been executed during testing.
You can turn it on by simply adding <code class="language-plaintext highlighter-rouge">enable_coverage :branch</code> into <code class="language-plaintext highlighter-rouge">SimpleCov.start</code> block.
Let’s enable it for my spec:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s1">'simplecov'</span>

<span class="no">SimpleCov</span><span class="p">.</span><span class="nf">start</span> <span class="k">do</span>
  <span class="n">enable_coverage</span> <span class="ss">:branch</span>
<span class="k">end</span>

<span class="nb">require_relative</span> <span class="s1">'./example2.rb'</span>

<span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="s1">'number_to_dollar'</span> <span class="k">do</span>
  <span class="n">subject</span> <span class="p">{</span> <span class="n">number_to_dollar</span><span class="p">(</span><span class="mf">2.56</span><span class="p">)</span> <span class="p">}</span>

  <span class="n">it</span> <span class="s1">'returns dollar and cents'</span> <span class="k">do</span>
    <span class="n">expect</span><span class="p">(</span><span class="n">subject</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s1">'2 dollar(s) 56 cent(s)'</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>In my <code class="language-plaintext highlighter-rouge">coverage/index.html</code> file I can see that my test doesn’t cover all the branches:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1 files in total.
5 relevant lines, 5 lines covered and 0 lines missed. ( 100.0% )
2 total branches, 1 branches covered and 1 branches missed. ( 50.0% )
</code></pre></div></div>

<p>Thanks to branch coverage it’s easy to identify that I missed a case when the cent part is zero.
Having that information I can add additional test for that case, see that it fails and fix my code.</p>

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

<p>As you can see even 100% line coverage is not enough to be sure that my code is correct and fully tested.
Branch coverage can help to identify missed cases and prevent potential bugs in the app.</p>]]></content><author><name></name></author><category term="ruby" /><category term="testing" /><summary type="html"><![CDATA[It's a common practice to measure the quality of tests using line coverage. Unfortunately, in some cases, it's not enough.]]></summary></entry><entry><title type="html">Dependency Injection in Ruby</title><link href="https://kukicola.io/posts/dependency-injection-in-ruby/" rel="alternate" type="text/html" title="Dependency Injection in Ruby" /><published>2022-02-07T00:00:00+00:00</published><updated>2022-02-07T00:00:00+00:00</updated><id>https://kukicola.io/posts/dependency-injection-in-ruby</id><content type="html" xml:base="https://kukicola.io/posts/dependency-injection-in-ruby/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Dependency Injection isn’t something that you’ll see in every Rails application. 
Ruby allows us to stub basically everything in tests so in most cases there’s no need to inject any dependencies and hard-coding them is good enough.
Although even in such flexible language as ruby there is a place for DI.</p>

<h2 id="what-is-di">What is DI?</h2>
<p>Before we jump to some examples let’s first take a minute to understand what is Dependency Injection.
Imagine a situation when one of your services uses another one. You probably see it every day.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ServiceA</span>
  <span class="c1"># ...</span>
  <span class="k">def</span> <span class="nf">do_something</span>
    <span class="c1"># ...</span>
    <span class="no">ServiceB</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">do_something_else</span>
    <span class="c1"># ...</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ServiceB</code> is hard-coded and tightly coupled with <code class="language-plaintext highlighter-rouge">ServiceA</code>. Is that a bad thing? In most cases - no. 
We can still stub it in the tests or replace it with something else but it will be easier using DI.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ServiceA</span>
  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="ss">some_dependency: </span><span class="no">ServiceB</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
    <span class="vi">@some_dependency</span> <span class="o">=</span> <span class="n">some_dependency</span>
  <span class="k">end</span>

  <span class="c1"># ...</span>
  <span class="k">def</span> <span class="nf">do_something</span>
    <span class="c1"># ...</span>
    <span class="vi">@some_dependency</span><span class="p">.</span><span class="nf">do_something_else</span>
    <span class="c1"># ...</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Instead of hard-coding <code class="language-plaintext highlighter-rouge">ServiceB</code>, we are injecting it into <code class="language-plaintext highlighter-rouge">ServiceA</code>. It gives us loose coupling between our services - <code class="language-plaintext highlighter-rouge">ServiceA</code> depends on abstraction.
We can use a different class without changing the implementation of <code class="language-plaintext highlighter-rouge">ServiceA</code> as long as it implements <code class="language-plaintext highlighter-rouge">do_something_else</code> method.</p>

<h2 id="real-world-examples">Real-world examples</h2>
<p>Looking at the code above you’ll probably think “why would I need to change ServiceB?” or “even if I have to, it’s not a problem” and in most cases, you would be right.</p>

<p>Let’s take a look at some real-world examples:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">DataExport</span>
  <span class="c1"># ...</span>
  <span class="k">def</span> <span class="nf">call</span>
    <span class="n">csv</span> <span class="o">=</span> <span class="no">Writers</span><span class="o">::</span><span class="no">CSV</span><span class="p">.</span><span class="nf">new</span>
    <span class="n">csv</span> <span class="o">&lt;&lt;</span> <span class="n">some_data</span>
    <span class="c1"># ...</span>
    <span class="n">csv</span><span class="p">.</span><span class="nf">close</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Our class is responsible for exporting some data to a CSV file using <code class="language-plaintext highlighter-rouge">Writers::CSV</code>. 
Now imagine having many similar classes responsible for exporting different data in your application.</p>

<p>What if we decide to switch to XLS or give users a choice? How should we test it? Should it write to some temp files or should we stub it?</p>

<p>Second one:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SomeNotifier</span>
  <span class="c1"># ...</span>
  <span class="k">def</span> <span class="nf">call</span>
    <span class="c1"># ... </span>
      <span class="no">SmsSender</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="n">number</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
    <span class="c1"># ...</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>

<p>In this case, our class notifies users using an SMS message.</p>

<p>What if we decide to change the SMS provider? Easy - let’s just change <code class="language-plaintext highlighter-rouge">SmsSender</code> implementation.
How should we test it? Also easy - let’s just stub the whole class. But how it should behave in the development environment? 
We would probably want to avoid sending real sms messages and printing content to stdout should be enough. 
How would you handle it? <code class="language-plaintext highlighter-rouge">if Rails.development?</code> ?</p>

<h2 id="dependency-injection-to-the-rescue">Dependency Injection to the rescue</h2>

<p>Let’s focus on data export first. Using DI it would look like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">DataExport</span>
  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="ss">writer: </span><span class="no">Writers</span><span class="o">::</span><span class="no">CSV</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
    <span class="vi">@writer</span> <span class="o">=</span> <span class="n">writer</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
  <span class="k">def</span> <span class="nf">call</span>
    <span class="n">writer</span> <span class="o">&lt;&lt;</span> <span class="n">some_data</span>
    <span class="c1"># ...</span>
    <span class="n">writer</span><span class="p">.</span><span class="nf">close</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>

<p>We can easily replace the writer with some <code class="language-plaintext highlighter-rouge">Writers::XLS</code> or anything else without touching the actual implementation of <code class="language-plaintext highlighter-rouge">DataExport</code>.</p>

<p>In tests for this particular class we don’t really care if a file is created on the disk (assuming we have proper tests for <code class="language-plaintext highlighter-rouge">Writer::*</code>).
What we focus on is if exported data is correct. Do we need a real file for that? 
No, we can replace our writer with some <code class="language-plaintext highlighter-rouge">Writers::Memory</code>, which uses StringIO instead, without any stubs.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">describe</span> <span class="no">DataExport</span> <span class="k">do</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:instance</span><span class="p">)</span> <span class="p">{</span> <span class="n">described_class</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">writer: </span><span class="no">Writers</span><span class="o">::</span><span class="no">Memory</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span> <span class="p">}</span>
  
  <span class="n">it</span> <span class="s1">'exports correct data'</span> <span class="k">do</span>
    <span class="c1"># ...</span>
    <span class="n">expect</span><span class="p">(</span><span class="n">writer</span><span class="p">.</span><span class="nf">result</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="n">something</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Since our test is using memory instead of real files it can result in a significant performance boost. 
Also, we don’t have any stubs that distract us from what’s important in our test.</p>

<p>To solve our problem from the second example we have to go further.</p>

<h2 id="dependency-container">Dependency Container</h2>

<p>Dependency Container helps us keep our dependencies in one centralized place. 
We have a great implementation called <a href="https://dry-rb.org/gems/dry-container/">dry-container</a>.</p>

<p>First, we need to initialize the container and register our dependencies:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">container</span> <span class="o">=</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Container</span><span class="p">.</span><span class="nf">new</span>
<span class="n">container</span><span class="p">.</span><span class="nf">register</span><span class="p">(</span><span class="ss">:sms_service</span><span class="p">,</span> <span class="no">SmsSender</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
</code></pre></div></div>

<p>Then, we can use it in our <code class="language-plaintext highlighter-rouge">SomeNotifier</code> class.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SomeNotifier</span>
  <span class="c1"># ...</span>
  <span class="k">def</span> <span class="nf">call</span>
    <span class="c1"># ... </span>
    <span class="n">container</span><span class="p">.</span><span class="nf">resolve</span><span class="p">(</span><span class="ss">:sms_service</span><span class="p">).</span><span class="nf">call</span><span class="p">(</span><span class="n">number</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
    <span class="c1"># ...</span>
  <span class="k">end</span>
  <span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Now <code class="language-plaintext highlighter-rouge">SmsSender</code> is used directly only during container initialization. As a result, we can easily register different classes in different environments.
In our development we can register some fake class that will output the message to stdout:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">container</span> <span class="o">=</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Container</span><span class="p">.</span><span class="nf">new</span>
<span class="n">container</span><span class="p">.</span><span class="nf">register</span><span class="p">(</span><span class="ss">:sms_service</span><span class="p">,</span> <span class="no">FakeSmsSender</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
</code></pre></div></div>

<p>Dependency Container can be extremely useful when working with external APIs and not just that.</p>

<h2 id="conclusion">Conclusion</h2>
<p>Both examples above can be handled without using DI. 
You can use stubs, <code class="language-plaintext highlighter-rouge">if Rails.development?</code> conditions, or any other tricks but in my opinion, DI makes it cleaner, easier to maintain and test.</p>

<p>It can be useful in many other cases:</p>
<ul>
  <li>working with external services - you don’t need tons of requests stubs and it’s easy to use fake data in the development</li>
  <li>when using repository pattern - fake repositories in tests instead of stubs or real calls to the database</li>
  <li>A/B testing different approaches/implementations</li>
</ul>

<p>If you don’t agree with me or have any other thoughts on the subject please let me know!</p>]]></content><author><name></name></author><category term="ruby" /><category term="di" /><summary type="html"><![CDATA[Dependency Injection is not a common pattern in ruby applications. Although even in such flexible language as ruby there is a place for DI.]]></summary></entry></feed>