<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Arkadiusz Chmura</title>
    <link>https://arkadiuszchmura.com/</link>
    <description>Recent content on Arkadiusz Chmura</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 10 Oct 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://arkadiuszchmura.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Things I learned while building a yt-dlp wrapper</title>
      <link>https://arkadiuszchmura.com/posts/things-i-learned-while-building-a-yt-dlp-wrapper/</link>
      <pubDate>Thu, 10 Oct 2024 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/things-i-learned-while-building-a-yt-dlp-wrapper/</guid>
      <description>An opportunity to learn new things is a great reason to pursue side project.</description>
      <content:encoded><![CDATA[<p>A couple of weeks ago, I launched <a href="https://clipsnag.com/">ClipSnag</a>, a native macOS wrapper for a popular command-line tool called <a href="https://github.com/yt-dlp/yt-dlp">yt-dlp</a>. The goal of this app is to provide the benefits of this wonderful tool to people who are not comfortable with a terminal or simply prefer GUI over command-line tools.</p>
<p>In this post, I would like to share the two things I learned while building this app:</p>
<h3 id="open-source-doesnt-mean-do-whatever-you-want">Open-source doesn&rsquo;t mean &ldquo;do whatever you want&rdquo;</h3>
<p>The fact that software is open-sourced doesn&rsquo;t mean you can do absolutely everything you want with it. Each open-source software is released under a specific license that describes how the software can be used, modified, and shared.</p>
<p>For example, the <code>yt-dlp</code> program is released under the <a href="https://github.com/yt-dlp/yt-dlp?tab=Unlicense-1-ov-file">&ldquo;Unlicense license&rdquo;</a>. It&rsquo;s a public domain equivalent license, which allows you to use, modify, distribute, or even sell the software without asking for permission or giving credit. This license would allow me to include <code>yt-dlp</code> as part of my own, paid app without any issues.</p>
<p>However, <code>yt-dlp</code> has several dependencies. All of them are optional, but two are highly recommended - <code>ffmpeg</code> and <code>ffprobe</code>, without which my app doesn&rsquo;t work. They are used for merging video and audio files, converting between formats, as well as for various post-processing tasks. Most of their codebases are released under the <a href="https://opensource.org/license/lgpl-2-1">&ldquo;LGPL v2.1+&rdquo;</a> license. The license states that any &ldquo;derivative&rdquo; work must be distributed under the same or equivalent license terms. This effectively means that if I were to bundle <code>ffmpeg</code> and <code>ffprobe</code> executables within my app, I would have to make the app open-source as well and provide it under the same license.</p>
<p>Since open-sourcing the app wasn&rsquo;t my intention, I had to find a different solution, and that solution would have to be aligned with the target audience for the app - potentially non-tech-savvy users. I wanted people to be able to download my app and start using it immediately without having to worry about downloading all of the necessary tools mentioned above manually. And how was I supposed to do that if I can&rsquo;t include them as part of my app because of the license restrictions?</p>
<p>The exploration related to this question brought me to my second finding:</p>
<h3 id="macos-allows-apps-to-download-and-execute-arbitrary-executables">macOS allows apps to download and execute arbitrary executables</h3>
<p>Firstly, let&rsquo;s see what happens from the user&rsquo;s perspective when they download an executable using their browser and try to run it.</p>
<p>On my machine (running macOS Sonoma), this is what I got after I <a href="https://evermeet.cx/ffmpeg/">downloaded</a> FFmpeg, unzipped it, and either opened it by double-clicking or typed <code>./ffmpeg</code> in my terminal:</p>
<figure class="align-center ">
    <img loading="lazy" src="/yt-dlp/1.png#center" width="300"/> 
</figure>

<p>The reason for this alert is the <a href="https://en.wikipedia.org/wiki/Gatekeeper_(macOS)">Gatekeeper</a> mechanism. By default, it verifies that any software you intend to run for the first time is from an identified developer, is notarised by Apple to be free of known malicious content (since macOS Catalina), and hasn’t been altered.</p>
<p>In this case, the <code>ffmpeg</code> binary isn&rsquo;t signed by a certified Apple Developer hence the warning that &ldquo;the developer cannot be verified&rdquo;. One way to work around this is to open System Settings, go to the &ldquo;Privacy &amp; Security&rdquo; tab, and click on &ldquo;Allow Anyway&rdquo; in the section mentioning <code>ffmpeg</code>:</p>
<figure class="align-center ">
    <img loading="lazy" src="/yt-dlp/2.png#center"/> 
</figure>

<p>Then we can run the program again and confirm the will to open:</p>
<figure class="align-center ">
    <img loading="lazy" src="/yt-dlp/3.png#center" width="350"/> 
</figure>

<p>As you can see, a lot of steps are required - downloading the archive, unzipping it, running the executable, clicking &ldquo;Allow Anyway&rdquo; in the settings, running again, and finally, confirming. Given that my app requires three external dependencies, which can&rsquo;t be bundled because of the license restrictions, the above steps would have to be performed three times, manually.</p>
<p>I considered preparing a detailed instruction for a manual installation of all of these tools for my users, but that would be way too much to ask from them, especially given that the app is paid. It should run out of the box, without any additional work.</p>
<p>This almost led me to abandon the app altogether, but then I realized that none of the above steps are necessary when downloading an executable using a non-browser tool, like <code>curl</code> or a simple Python script.</p>
<p>Why is that?</p>
<p>Firstly, it turns out that what triggers all of the Gatekeeper checks is the <code>com.apple.quarantine</code> extended attribute that is attached to all downloaded files.</p>
<p>If we run the <code>xattr</code> program (that&rsquo;s used to work with extended attributes) on the downloaded <code>ffmpeg</code> executable, we can see that indeed, this attribute is present:</p>
<figure class="align-center ">
    <img loading="lazy" src="/yt-dlp/4.png#center" width="350"/> 
</figure>

<p>Secondly, Gatekeeper will <strong>only</strong> verify applications that have the quarantine flag. The problem is that this flag is added by other applications, not by the operating system itself. It&rsquo;s the responsibility of app developers to make sure that this flag is added to any files downloaded by the app.</p>
<p>Apps like web browsers or email clients properly attach the quarantine flag to all downloaded files, but many don&rsquo;t, like most BitTorrent client software. The flag is also not added if the app came from a different source, like network shares or USB drives.</p>
<p>To illustrate this, let&rsquo;s download <code>ffmpeg</code> again, this time using <code>curl</code>. Then, when we unzip it and run <code>xattr</code> on the executable, we can see that there is no quarantine flag attached. Also, running doesn&rsquo;t trigger any OS alerts:</p>
<figure class="align-center ">
    <img loading="lazy" src="/yt-dlp/5.png#center"/> 
</figure>

<p>We bypassed all Gatekeeper checks by simply using a program that doesn&rsquo;t attach the quarantine flag (that&rsquo;s one of the reasons why this mechanism received some <a href="https://en.wikipedia.org/wiki/Gatekeeper_(macOS)#Implications">criticism</a>).</p>
<p>I used the exact same &ldquo;trick&rdquo; in my app. Instead of bundling <code>yt-dlp</code>, <code>ffmpeg</code>, and <code>ffprobe</code> within my app, which would violate their licenses, or requiring users to download them manually, I simply download the dependencies upon the first app launch and store them outside of the app in the user&rsquo;s home directory, without disrespecting the licenses.</p>
<p>Problem solved!</p>
<hr>
<p>One final, but very important, thing to note is that the above little experiment proves that it&rsquo;s always crucial to make sure that we only open apps we trust. On the surface, the <code>Gatekeeper</code> mechanism sounds great and you would think it fully protects your computer against running potentially malicious executables, but, as we&rsquo;ve seen, that&rsquo;s unfortunately not always the case.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Optimizing your workflow does matter in the long run</title>
      <link>https://arkadiuszchmura.com/posts/optimizing-your-workflow-does-matter-in-the-long-run/</link>
      <pubDate>Sun, 05 Nov 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/optimizing-your-workflow-does-matter-in-the-long-run/</guid>
      <description>Having your environment tailored to you and the way you work can save you from context switching, losing focus, reaching for your mouse, or simply wasting time.</description>
      <content:encoded><![CDATA[<p>There always seemed to be a group of programmers arguing that things like typing speed or a workflow tailored specifically to you and the way you work don&rsquo;t matter because these are not the bottleneck. They say it&rsquo;s the thinking process that takes most of the time and energy, and optimizing the part that comes after doesn&rsquo;t make much sense.</p>
<p>Let&rsquo;s leave the discussion about whether that&rsquo;s true aside for a moment. However, it&rsquo;s worth noting that the &ldquo;typing speed doesn&rsquo;t matter&rdquo; argument is often brought up by people who can&rsquo;t type quickly. Have you ever met a fast typer who wished they hadn&rsquo;t learned to type quickly because the speed was getting in their way? Similarly, it&rsquo;s usually people who are happily clicking around with their mouse, repeating the same actions over and over again, day after day, who claim that learning and configuring keyboard shortcuts of the editor you&rsquo;re using is a waste of time.</p>
<p>Not long ago, I was one of those people. Only after learning how to touch type have I noticed how effortless typing could be when you don&rsquo;t have to look at the keyboard all the time and can leverage all 10 of your fingers during the process. Likewise, I started to strongly appreciate the value of having keyboard shortcuts ingrained in my muscle memory and not needing to reach for my mouse as frequently as I used to.</p>
<p>Two weeks ago, I finished my second marathon. At first glance, running and programming don&rsquo;t have much in common. However, it was this race that has reinforced my conviction that optimizing your workflow does matter in the long run.</p>
<h3 id="the-race">The race</h3>
<p>Even though my fitness level was similar and my training plan almost identical, I managed to finish the race 10 minutes faster than my first marathon last year. It was focusing on the seemingly irrelevant details and having a much smarter strategy for the race that allowed me to arrive at the finish line earlier, feeling much better than last time.</p>
<p>During most officially organized races, you will encounter several aid stations. These are designated areas for runners to hydrate and refuel, usually positioned every few kilometers. At these stations, volunteers hold out cups of water to the runners so that they can grab them while still running.</p>
<p>Have you ever tried running and drinking from a cup simultaneously? When I first did that, I spilled almost all of it onto my face and nearly choked with little of what remained. There is always an option to stop for a moment and drink, but stopping is always risky because it might be challenging to force yourself to start running again.</p>
<p>It turns out that such a seemingly insignificant thing as the right technique for grabbing a cup of water can have a considerable impact on the final time. It&rsquo;s enough to squeeze the top of the cup, leaving a small hole to drink from, which allows you to take frequent, small sips like this:</p>
<figure class="align-center ">
    <img loading="lazy" src="/cap.jpg#center"
         alt="The &ldquo;pinch&rdquo; method for grabbing a cup of water. Source: Runner&rsquo;s World"/> <figcaption>
            <p>The &ldquo;pinch&rdquo; method for grabbing a cup of water. Source: <a href="https://www.runnersworld.com/training/a38174526/rw-plus-water-station-test/">Runner&rsquo;s World</a></p>
        </figcaption>
</figure>

<p>You might think it doesn&rsquo;t make a huge difference, but remember that a marathon is a long distance. You are likely to pass at least 8-12 of those stations throughout the race. Without a proper technique for drinking, you&rsquo;ll interrupt your breathing rhythm and lose much-needed focus, leaving the station frustrated and discouraged every time, all of which can contribute to a couple of additional minutes to your final time or a lack of satisfaction after finishing the race.</p>
<h3 id="back-to-programming">Back to programming</h3>
<p>This experience made me realize how beneficial it might be for us programmers to make our tools as efficient as possible, especially when we think about programming as a lifelong career or hobby.</p>
<p>That keyboard shortcut for a frequently used action we&rsquo;ve been diligently refining over the last weeks might seem silly to other people. Still, this very shortcut, which is now ingrained in our muscle memory, saves us from costly context switching, losing focus, reaching for our mouse, or simply wasting time. Having a bespoke workflow allows us to think purely in terms of &ldquo;what&rdquo; we want to do, not &ldquo;what and how&rdquo;.</p>
<p>Everyday tasks like <a href="https://arkadiuszchmura.com/posts/switching-between-apps-using-shortcuts-on-macos/">switching between apps</a>, running tests for our project, jumping to a specific file in the editor, or renaming a variable are performed by us dozens of times per day, so why would anyone argue that making sure these things are easily and quickly accessible is a waste of time?</p>
<p>Part of the reason might be that the gains are not clearly noticeable, as they are in running, for instance. When you introduce some changes, like the technique mentioned above for grabbing a cup of water or a carbon-plated pair of shoes, you can quickly tell whether it worked by simply checking your finish time. It&rsquo;s more complex with programming because there is no obvious metric we can compare - it&rsquo;s mostly subjective.</p>
<p>Therefore, drawing an analogy from other disciplines where the results are more tangible can help us visualize the importance of removing the minor pain points we encounter multiple times per day, specifically when we think about programming as a marathon, not a short park run.</p>
<h3 id="the-joy-aspect">The joy aspect</h3>
<p>Another benefit of having a personal, customized environment that makes repetitive tasks easy and fun is that you will derive satisfaction from using it.</p>
<p>For example, when you have a keyboard that gives you joy with every keystroke, you’re more likely to come back to programming repeatedly and consistently because just the idea of being able to type on that keyboard again might be enough to motivate you to keep working on your side projects.</p>
<p>Similarly, having a script that puts a smile on your face every time it&rsquo;s executed, potentially saving you seconds or even minutes of manual labor, is well worth it. All of this contributes to an overall joyful experience.</p>
<p>In contrast, having tools that work against you rather than with you might cause resentfulness to the mere idea of having to program again. A keyboard that causes pain in your wrists will make you come up with excuses to avoid typing as much as possible, and you might find yourself writing less helpful code review comments, shorter and ambiguous documentation, or confusing messages to your colleagues.</p>
<p>After all, wouldn’t it be a good idea to allow the mind to focus on abstract and complex problems, which supposedly are the bottleneck, instead of thinking about the distracting little details that can get in the way?</p>
<hr>
<p>I hope you found this post useful. If you have some questions or thoughts, leave a comment here or reach out to me on <a href="https://x.com/ClouddJR/">X</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Accessing cheatsheets from the command line</title>
      <link>https://arkadiuszchmura.com/posts/accessing-cheatsheets-from-the-command-line/</link>
      <pubDate>Sun, 08 Oct 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/accessing-cheatsheets-from-the-command-line/</guid>
      <description>The cheat.sh utility allows you to access a lot of comprehensive, community-driven cheatsheets for many popular tools.</description>
      <content:encoded><![CDATA[<h2 id="the-problem">The problem</h2>
<p>Very often, I know which command line tool would come in handy for a given task at hand, but I can&rsquo;t recall the exact syntax I should use or the options that are available to me.</p>
<p>Looking into the documentation is definitely an option, but they sometimes lack practical examples. Also, usually, I&rsquo;m already familiar with this tool, but I just need a quick refresher.</p>
<h2 id="the-solution">The solution</h2>
<p>Meet <a href="https://github.com/chubin/cheat.sh">cheat.sh</a>. An open-source tool that gives you access to community-driven cheatsheets for programming languages, DBMSes, and command line tools through a simple interface.</p>
<p>Want a <a href="https://xkcd.com/1168/">quick overview</a> of the <code>tar</code> utility? Just type this in your terminal, no installation required:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl cht.sh/tar
</span></span></code></pre></div><p>You&rsquo;ll get answers from multiple cheatsheets repositories at the same time. The screenshot below shows the part of the response that comes from the <a href="https://tldr.sh/">https://tldr.sh/</a> website:</p>
<figure class="align-center ">
    <img loading="lazy" src="/cheatsh/tar.png#center"/> 
</figure>

<p>It also works for programming languages. For example, to learn about list comprehension in Python, you could use this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl cht.sh/python/list_comprehension
</span></span></code></pre></div><blockquote>
<p>To get a list of topics available for a given language, execute <code>curl cht.sh/python/:list</code>. Additionally, most languages have a special <code>:learn</code> page that describes the basics to get you started quickly.</p>
</blockquote>
<h3 id="command-line-client">Command line client</h3>
<p>If you don&rsquo;t want to constantly type the <code>curl</code> command to access the cheatsheets, you can install the command line client according to the <a href="https://github.com/chubin/cheat.sh#command-line-client-chtsh">instructions</a> on the GitHub page. There is also an option to activate tab completion support.</p>
<p>I did all of the above and created a custom bash function called <code>c</code> that executes the script and also pipes the result to the <code>less</code> program for convenience (the <code>&quot;$@&quot;</code> part refers to arguments passed to the function).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">function</span> c<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$HOME</span>/.dotfiles/shell/scripts/cht.sh <span class="s2">&#34;</span><span class="nv">$@</span><span class="s2">&#34;</span> <span class="p">|</span> less
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></div><p>After doing that, I can start typing <code>c ff</code> and instantly get suggestions matching the query:</p>
<figure class="align-center ">
    <img loading="lazy" src="/cheatsh/ffmpeg.gif#center"/> 
</figure>

<p>If you&rsquo;re interested, here&rsquo;s a <a href="https://github.com/ClouddJR/dotfiles/commit/6b95fd1ee4e2d343d148336fa4d85ad8a230ad97">commit</a> in my dotfiles repository where I added this tool (notice the <code>#compdef c</code> line at the top of the <code>_cth</code> file that was necessary to get tab completion for my custom function).</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Making the most of GitHub Code Search</title>
      <link>https://arkadiuszchmura.com/posts/making-the-most-of-github-code-search/</link>
      <pubDate>Sat, 30 Sep 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/making-the-most-of-github-code-search/</guid>
      <description>The new search engine offers powerful code searching mechanisms we can leverage for quickly finding the code we need, as well as for exploration and learning.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>The GitHub Code Search tool was launched as a technical preview in December 2021. Almost 1.5 years later, in May 2023, it was made generally available to all GitHub users.</p>
<p>Fortunately, I was one of the developers who got access to the early versions of the new search engine. Months of exploration and largely positive experience led me to include this tool as an essential part of my daily workflow.</p>
<p>In this post, I will explain what makes this tool great not merely for searching code, but also for exploration and learning.</p>
<h2 id="overview-of-github-code-search">Overview of GitHub Code Search</h2>
<p>You can access the new search tool by clicking on the search bar at the top of the GitHub website, by pressing the <code>/</code> character, or by going straight to <a href="https://github.com/search">https://github.com/search</a>.</p>
<p>The documentation for code search syntax can be found
<a href="https://docs.github.com/en/search-github/github-code-search/understanding-github-code-search-syntax">under this link</a>, but here&rsquo;s a quick overview of what you can do:</p>
<ul>
<li>Searching for <code>index</code> will return files containing the term &ldquo;index&rdquo; in their content or path. So it would return both <code>public/index.php</code>, even if it doesn&rsquo;t contain the term &ldquo;index&rdquo;, and <code>public/sitemap.xml</code>, if it does.</li>
<li>Search supports boolean expressions. You can use <code>AND</code>, <code>OR</code>, and <code>NOT</code> operators. For example, the <code>bitmap OR index</code> query will return files containing the term &ldquo;bitmap&rdquo; or &ldquo;index&rdquo;, in any order. The <code>bitmap index</code> query uses an explicit <code>AND</code> operator, so it&rsquo;s equivalent to <code>bitmap AND index</code>. Parenthesis can be used to compose more complex expressions, like <code>bitmap AND (index OR header)</code>.</li>
<li>To search for an exact string, including whitespace, you can surround the query with double quotes. If your query contains quotation marks, you can escape them with a backslash. For instance, to search for the <code>&quot;license&quot;: &quot;MIT&quot;</code> string, we could use the <code>&quot;\&quot;license\&quot;: \&quot;MIT\&quot;&quot;</code> query.</li>
<li>It&rsquo;s possible to use regular expressions. You can do that by surrounding the expression with slashes. For example, to search for Polish postal codes, we could use the <code>/\d{2}-\d{3}/</code> query.</li>
<li>You can narrow your search using special qualifiers, like <code>org:github</code>, <code>user:ClouddJR</code>, <code>language:ruby</code>, <code>path:*.txt</code> (notice the <code>path:</code> qualifier supports glob expressions), or <code>symbol:HelloController</code>. You can see the full list of available qualifiers with an explanation <a href="https://docs.github.com/en/search-github/github-code-search/understanding-github-code-search-syntax#using-qualifiers">here</a>.</li>
</ul>
<p>Results for code search are always restricted to 100 results (5 pages). At the time of writing this post, sorting is not supported, although some heuristics are used to prioritize more meaningful results. In most cases, you can expect results from popular repositories to appear first.</p>
<p>There are other limitations worth keeping in mind, like the fact that large repositories might not be indexed at all. The same applies to long lines (over 1024 characters) and files (over 350 KiB). <a href="https://docs.github.com/en/search-github/github-code-search/about-github-code-search#limitations">Here</a> you can find a list of all current limitations.</p>
<h3 id="saved-searches">Saved searches</h3>
<p>If you find yourself typing the same query over and over again, you might want to use the mechanism for saving searches.</p>
<p>To do that, type <code>saved:</code> in the search bar and click on &ldquo;Manage saved searches&rdquo;. You can add your query there, which will be visible in the &ldquo;Saved queries&rdquo; section when you later access the search bar.</p>
<h3 id="advanced-search-page">Advanced search page</h3>
<p>This post focuses specifically on GitHub Code Search. If you want to search for non-code content, like issues, you can go to the <a href="https://github.com/search/advanced">advanced search page</a>. This page provides a visual interface for constructing search queries so that you don&rsquo;t have to remember all the available options.</p>
<p>However, if you prefer to type your queries manually, <a href="https://docs.github.com/en/search-github/searching-on-github">here&rsquo;s</a> a documentation for qualifiers that can be used when searching for non-code content.</p>
<p>Remember that you can use the same search bar for both code and non-code searches, although the syntax might differ.</p>
<h2 id="examples">Examples</h2>
<p>After using the new code search for some time, I found myself using some features more frequently than others. This section will show you the most popular use cases for this tool in my workflow.</p>
<h3 id="learning-a-new-api">Learning a new API</h3>
<p>When learning something new, it makes sense to see some practical examples. They can often be found in the official documentation, but that is not always the case.</p>
<p>Using the search engine, you can find real-life examples of the technology you&rsquo;re exploring. For example, let&rsquo;s say you&rsquo;re learning SwiftUI and would like to see some examples of how to use the <code>NavigationStack</code> in practice.</p>
<p>You can do that with this simple query: <code>&quot;NavigationStack {&quot; language:Swift</code>.</p>
<p>This approach has another benefit. While searching for the code you need, you might find some interesting repositories you were unaware of.</p>
<h3 id="searching-for-options">Searching for options</h3>
<p>Recently, I tried to extend the size of my shell&rsquo;s history. I knew the options I had to modify in my <code>.zshrc</code> file, but I didn&rsquo;t know what values are used for these options in practice.</p>
<p>A quick search across the GitHub repositories with the <code>HISTFILESIZE language:Shell</code> query showed me what values are common in many dotfiles repositories.</p>
<h3 id="inspiration-for-key-bindings">Inspiration for key bindings</h3>
<p>If you want to find out how people configure their tools, like editors, using the search engine can be a great option.</p>
<p>For instance, to see what keymaps people use for finding files using <a href="https://github.com/nvim-telescope/telescope.nvim">Telescope</a> in <a href="https://neovim.io/">Neovim</a>, you could search for <code>builtin.find_files language:Lua</code>.</p>
<h3 id="readme-files">README files</h3>
<p>Writing good documentation is hard. Therefore, when doing this ourselves, it might make sense to get some inspiration by reading some well-written README files available on GitHub.</p>
<p>By using the <code>path:/(^|\/)README\.md$/</code> query, we can find some <code>README.md</code> files from popular repositories. But obviously, the popularity of a repository doesn&rsquo;t always have to correlate to the quality of its README file.</p>
<h3 id="definition-of-a-class">Definition of a class</h3>
<p>The <code>symbol:</code> qualifier is one of the most useful ones. You could use it to find the definition of a specific class (or any other symbol, like a function) when you don&rsquo;t know the repository the class is in. The query could look like this: <code>symbol:HelloController org:github language:Ruby</code>.</p>
<p>This way of searching is especially handy when your company uses a microservices architecture and the code is distributed across hundreds (or thousands) of repositories.</p>
<p>You can check out <a href="https://docs.github.com/en/search-github/github-code-search/understanding-github-code-search-syntax#symbol-qualifier">this link</a> for a list of supported languages for symbol searching.</p>
<h3 id="sensitive-information">Sensitive information</h3>
<p>Unfortunately, with the power of the new search tool, it&rsquo;s now almost effortless to find repositories that contain sensitive information (like API keys for Firebase, etc.)</p>
<p>The <code>&quot;\&quot;current_key\&quot;: &quot; path:google-services.json</code> query reveals a lot of unprotected repositories.</p>
<blockquote>
<p>Note that even though the <code>google-services.json</code> file itself is considered safe to share with other people, it may contain additional information about your resources, like your database URL. If your security rules are not configured properly, an attacker could use that against you.</p>
</blockquote>
<p>However, we could use this capability to find repositories in our organization that expose sensitive information and address these vulnerabilities immediately.</p>
<h2 id="additional-resources">Additional resources</h2>
<p>I hope you found this post useful. If you have some questions, leave a comment here or reach out to me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
<p>If you&rsquo;d like to learn more about the technology behind the new search tool, here are some additional resources I recommend:</p>
<ul>
<li><a href="https://github.blog/2023-02-06-the-technology-behind-githubs-new-code-search/">https://github.blog/2023-02-06-the-technology-behind-githubs-new-code-search/</a> - a high-level overview of the design and architecture of the new code search.</li>
<li><a href="https://github.blog/2021-12-15-a-brief-history-of-code-search-at-github/">https://github.blog/2021-12-15-a-brief-history-of-code-search-at-github/</a> - a brief history of previous attempts at building a search engine suitable for GitHub&rsquo;s scale and an explanation of why building from scratch was necessary despite existing open-source solutions.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Switching between apps using shortcuts on macOS</title>
      <link>https://arkadiuszchmura.com/posts/switching-between-apps-using-shortcuts-on-macos/</link>
      <pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/switching-between-apps-using-shortcuts-on-macos/</guid>
      <description>This is one of the most common activities when working on a computer. To make it as seamless as possible, I assigned a custom shortcut for every app I commonly use.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>As a developer, I&rsquo;m always interested in different ways to improve my workflow, especially when it comes to tasks I perform frequently every single day. Switching between apps is one of those things.</p>
<p>I was looking for an option that would allow me to switch between apps as smoothly as possible without thinking too much about it or having to reach for my mouse.</p>
<h2 id="why-werent-existing-options-enough">Why weren&rsquo;t existing options enough?</h2>
<h4 id="using-the-dock">Using the dock</h4>
<p>This option requires a mouse, which disqualifies it completely. Additionally, it only lets you switch between already running apps. You can&rsquo;t launch an app unless you have it pinned in the dock.</p>
<h4 id="cmd--tab">CMD + Tab</h4>
<p>This technique works fine when switching between the two most recently used apps. However, if you regularly access more than two apps, you will often find yourself examining the CMD + Tab menu looking for the app you want to switch to.</p>
<p>Additionally, as with the previous option, you can only switch between already running apps. Launching is not possible.</p>
<h4 id="searching-with-spotlight-or-alternatives">Searching with Spotlight (or alternatives)</h4>
<p>These tools are great for launching apps but not so great for quick switching. Not only do you have to use a shortcut to trigger the search bar first (usually CMD + space), but also type at least a couple of characters to find the app you&rsquo;re looking for.</p>
<h4 id="stage-manager">Stage Manager</h4>
<p><a href="https://support.apple.com/en-gb/HT213315">This feature</a> has been introduced in macOS Ventura. Although it seems really useful at first glance, it&rsquo;s still mainly a mouse/trackpad-oriented feature.</p>
<h2 id="solution-custom-shortcuts">Solution: custom shortcuts</h2>
<p>The technique that proved to be the most effective one for me was assigning a custom keyboard shortcut for every app I use frequently.</p>
<p>To do that, I first remapped the right command to act as the so-called hyper key (using <a href="https://karabiner-elements.pqrs.org">Karabiner</a>). This means that when I press the right command, it acts as if the CTRL+SHIFT+CMD+OPT modifiers were pressed simultaneously. This combination is pretty much guaranteed not to conflict with anything else on your computer. What kind of app would define a shortcut involving all four modifiers anyway?</p>
<p>Next, I defined shortcuts for some of my apps using the hyper key. I did that in the <a href="https://www.raycast.com/">Raycast</a> app. It was the easiest option for me because I have already been using it as a Spotlight alternative anyway. However, if you don&rsquo;t use Raycast, any other tool would work just fine for that purpose, like <a href="https://folivora.ai/">BetterTouchTool</a>.</p>
<figure class="align-center ">
    <img loading="lazy" src="/shortcuts/raycast.png#center"
         alt="Assigning hyper key &#43; t shortcut to access iTerm in Raycast&rsquo;s settings."/> <figcaption>
            <p>Assigning hyper key + t shortcut to access iTerm in Raycast&rsquo;s settings.</p>
        </figcaption>
</figure>

<p>After these changes, I am always a single keyboard shortcut away from apps I commonly use. This is what my workflow looks like in practice:</p>
<figure class="align-center ">
    <img loading="lazy" src="/shortcuts/workflow.gif#center"
         alt="My workflow for quickly switching between apps using shortcuts."/> <figcaption>
            <p>My workflow for quickly switching between apps using shortcuts.</p>
        </figcaption>
</figure>

<p>This approach has another benefit of being able to launch the app if it wasn&rsquo;t running already and also switch focus to another monitor or space if the app is somewhere else at the time of pressing the shortcut.</p>
<h3 id="switching-between-spaces">Switching between spaces</h3>
<p>Besides assigning shortcuts for apps, I assigned shortcuts for spaces. In practice, I use them less often, but they can be valuable in some situations, like when I have multiple apps&rsquo; windows arranged in a certain way in various spaces and want to switch between them quickly.</p>
<p>You can do that in the system settings without installing any third-party app by going to <code>Keyboard</code> -&gt; <code>Keyboard Shortcuts</code> -&gt; <code>Mission Control</code> (make sure first to open some spaces because these options won&rsquo;t be visible otherwise):</p>
<figure class="align-center ">
    <img loading="lazy" src="/shortcuts/spaces.png#center"
         alt="Assigning shortcuts for spaces in the system settings (I used the hyper key again here)."/> <figcaption>
            <p>Assigning shortcuts for spaces in the system settings (I used the hyper key again here).</p>
        </figcaption>
</figure>

<p>I was slightly annoyed by the default transition animation when switching between spaces. Luckily, it can be minimized by turning on the <code>Reduce motion</code> option in the system settings (under <code>Accessibility</code> -&gt; <code>Display</code>). Keep in mind that it won&rsquo;t get rid of that animation completely. There are ways to turn it off completely, but they all require disabling the <a href="https://en.wikipedia.org/wiki/System_Integrity_Protection">System Integrity Protection</a>, which I&rsquo;m not interested in doing (especially on a work laptop).</p>
<h2 id="summary">Summary</h2>
<p>I hope you found this post useful. If you have some ideas about how this workflow could be improved even further, let me know here in the comments section or reach out to me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Stop perfecting your config</title>
      <link>https://arkadiuszchmura.com/posts/stop-perfecting-your-config/</link>
      <pubDate>Fri, 21 Jul 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/stop-perfecting-your-config/</guid>
      <description>It&amp;rsquo;s never going to be perfect anyway. Learn to accept the &amp;ldquo;good enough&amp;rdquo; and move on to more meaningful things.</description>
      <content:encoded><![CDATA[<p>Are you one of those people who spend countless hours tinkering with configuration for their editors, IDEs, terminals, or other applications? Do you find yourself spending more time on this never-ending rabbit hole of micro-configuration than on actual programming? If the answer is yes (as it was for me at some point), it&rsquo;s about time you stopped wasting your time.</p>
<p>In this post, I will discuss potential reasons behind this behavior, offer some strategies to overcome it and talk about other serious problems that it may lead to.</p>
<p>Before I continue, let&rsquo;s make one thing clear. By no means am I saying that there is something wrong with trying to master your tools or attempting to adjust them to suit your specific needs. It&rsquo;s actually the opposite. I think it&rsquo;s a great investment of your time that will make you a more efficient and productive developer in the end.</p>
<p>However, it&rsquo;s important to recognize when constant configuration becomes an obsession and a meaningless search for perfection that&rsquo;s impossible to achieve anyway. It&rsquo;s time to learn to accept the &ldquo;good enough&rdquo; and move on to more meaningful things that will truly bring you closer to your goals.</p>
<h3 id="people-are-obsessed-with-configs">People are obsessed with configs</h3>
<p>If you were to go on YouTube right now and find any video related to programming, I bet some of the top comments would be one of the following:</p>
<ul>
<li>What&rsquo;s the editor/terminal that you use?</li>
<li>What&rsquo;s the name of that color scheme and font in your editor?</li>
<li>Do you have a link to your dotfiles repository?</li>
</ul>
<p>Very often, it seems that people completely ignore the content of the video and simply come to the comments section to ask these questions. Why is that? Why are people so obsessed with these seemingly irrelevant details?</p>
<p>One potential reason is that spending time configuring the environment makes people feel productive and can provide a sense of achievement. Yes, you aren&rsquo;t working on what you should be working on, but at least you are spending time with the tools you normally work with, so you don&rsquo;t feel guilty. However, the harsh reality is that it&rsquo;s simply a way of procrastination. It&rsquo;s trickier to spot because it&rsquo;s not as obvious as watching TV or playing video games, but the end result is the same - no work is being done.</p>
<p>Another reason is much more profound. In his excellent <a href="https://www.youtube.com/watch?v=VO6XEQIsCoM">TED talk</a>, called &ldquo;The paradox of choice&rdquo;, Barry Schwartz argues that all of the choice we have in today&rsquo;s world produces paralysis rather than liberation. With so many options to choose from, people find it very difficult to choose at all. He gave an example of a study on investments in voluntary retirement plans. What was found was that for every 10 mutual funds the employer offered, the rate of participation went down 2%. You offer 50 funds, 10% fewer people participate than if you only offer 5. Why? Because with 50 different options, it&rsquo;s so damn hard to decide which fund to choose that eventually, people end up not choosing at all.</p>
<p>We can clearly see this phenomenon at play with highly customizable editors like Neovim, where the customization options are almost endless. There are so many plugins to install, so many options to explore and so many color schemes and fonts to choose, that people feel paralyzed and simply look for someone else to make that decision for them. This perfectly explains the flood of questions we see everywhere about other people&rsquo;s setups.</p>
<p>Another thing is that even if we manage to overcome the paralysis and finally make a choice, the fact that we had so many options to choose from makes us less satisfied with our choice than if we only had a handful of alternatives. Why? Because it&rsquo;s easy to imagine that we could&rsquo;ve made a different choice that would&rsquo;ve been better. That imagination causes us to question the correctness of our choice. If you only had one option instead, there would be absolutely no overthinking, because there was no other choice anyway.</p>
<p>Once again, we can transfer that observation to our domain. The fact that we have so many customization options for our work environment makes some of us feel that what we have right now is not enough, and there awaits a perfect keymap or color scheme right around the corner that will make our setup perfect. It&rsquo;s easy to imagine that if we just had a different terminal setup or a different IDE, we would become much better programmers.</p>
<h3 id="accept-the-good-enough">Accept the good enough</h3>
<p>Now that we know some potential reasons as to why people spend so much time on configuration, let&rsquo;s talk about what we can do about it.</p>
<p>The first and most important step is realizing that the perfect setup doesn&rsquo;t exist and will never be achieved. That realization in itself might be very liberating and free us from perfectionism, which is the enemy of progress.</p>
<p>As an example, learning to accept the &ldquo;good enough&rdquo; allowed me to setup this blog from scratch one year ago in a single evening. I used a free theme created by someone else. It was far from perfect and there were things I didn&rsquo;t like. Also, I didn&rsquo;t have a comments section or any other way for people to engage with my content. But I was completely fine with that since my goal was to start writing and not tinker with yet another configuration, so I resisted that urge.</p>
<p>However, if that little mindset shift is not enough for you, it might make sense to introduce some small rules for yourself. I suggest following <a href="https://www.youtube.com/@ThePrimeagen">ThePrimeagen&rsquo;s</a> advice on approaching your configuration. He recommends revisiting your configuration only once every couple of months, which I think is a very healthy and sustainable approach. In the meantime, take a mental note of the things that are annoying or slowing you down so that you can address them when the time to overhaul comes.</p>
<p>On the other hand, if your goal is to start with an editor like Neovim, don&rsquo;t bother initially trying to setup everything on your own. Just copy a config from someone you follow that uses Neovim or start with this really cool project called <a href="https://github.com/nvim-lua/kickstart.nvim">kickstart.nvim</a>. That will allow you to start using the editor as soon as possible so that you can see whether it&rsquo;s something for you or not. And then, after some time, you will know which things need to be adjusted.</p>
<h3 id="stay-away-if-youre-a-beginner">Stay away if you&rsquo;re a beginner</h3>
<p>I would argue that the consequences of perfectionism can be more severe if you&rsquo;re just starting out in programming. If that&rsquo;s the case, stay away from all of that for as long as possible. Your goal is to learn programming, so focus on that. Learn the fundamentals first. The time to learn and configure tools will come eventually, but this is definitely not the right time yet. If you try to do everything at once, you will be frustrated and overwhelmed. That may ultimately cause you to give up programming entirely.</p>
<p>The urge might be really strong because being able to engage in online discussions about editors, IDEs, and terminal setups (or understand memes) can give you a sense of belonging to the programmer&rsquo;s community. But please, don&rsquo;t let these shiny things distract you from your real goal, which is learning how to program.</p>
<h3 id="its-not-just-about-configs">It&rsquo;s not just about configs</h3>
<p>Honestly, it would be great if all of this was only about tinkering with our configuration. At the end of the day, who cares that some of us might spend a couple of hours every single day searching for the perfect color scheme for our Neovim setup?</p>
<p>Unfortunately, the problem with striving for perfectionism is that it can also manifest itself in other, much more significant, aspects of our lives. For instance, not realizing that &ldquo;perfect&rdquo; doesn&rsquo;t exist can make you feel dissatisfied with your current partner, the place where you live, or the job you have. This could also mean that you may end up waiting for the perfect moment in your life to start chasing your goals, which will obviously never come.</p>
<p>If the arguments presented in previous sections weren&rsquo;t convincing enough, let this motivate you to fix your obsession with configuration because, as you can see, your overall well-being is at stake.</p>
<h3 id="summary">Summary</h3>
<p>I hope you found this post useful. I wrote it as much for you as for myself - to constantly remind myself that striking a balance between spending time on customization and actual coding is essential. And again, as I mentioned multiple times throughout this post, remember that it&rsquo;s not merely about our configs in the end.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to dynamically change UIStackView axis</title>
      <link>https://arkadiuszchmura.com/posts/how-to-dynamically-change-uistackview-axis/</link>
      <pubDate>Fri, 30 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-dynamically-change-uistackview-axis/</guid>
      <description>Let&amp;rsquo;s see how we can change the axis from horizontal to vertical once the elements no longer fit the screen properly.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Recently, when working on an iOS app, I had to adjust the UI to work correctly with increased font size.</p>
<p>I had a <code>UIStackView</code> with its children laid horizontally - a <code>UILabel</code> and a <code>UIButton</code>. This is what the UI looked like:</p>
<figure class="align-center ">
    <img loading="lazy" src="/uistackview/ui.png#center" width="300"/> 
</figure>

<p>And this is the code representing the stack and its elements:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kr">lazy</span> <span class="kd">var</span> <span class="nv">stackView</span><span class="p">:</span> <span class="n">UIStackView</span> <span class="p">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">stackView</span> <span class="p">=</span> <span class="n">UIStackView</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">stackView</span><span class="p">.</span><span class="n">spacing</span> <span class="p">=</span> <span class="mf">16.0</span>
</span></span><span class="line"><span class="cl">    <span class="n">stackView</span><span class="p">.</span><span class="n">distribution</span> <span class="p">=</span> <span class="p">.</span><span class="n">equalSpacing</span>
</span></span><span class="line"><span class="cl">    <span class="n">stackView</span><span class="p">.</span><span class="n">translatesAutoresizingMaskIntoConstraints</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">stackView</span>
</span></span><span class="line"><span class="cl"><span class="p">}()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">private</span> <span class="kr">lazy</span> <span class="kd">var</span> <span class="nv">label</span><span class="p">:</span> <span class="n">UILabel</span> <span class="p">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">label</span> <span class="p">=</span> <span class="n">UILabel</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">label</span><span class="p">.</span><span class="n">text</span> <span class="p">=</span> <span class="s">&#34;Lorem ipsum dolor&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">label</span><span class="p">.</span><span class="n">font</span> <span class="p">=</span> <span class="n">UIFont</span><span class="p">.</span><span class="n">preferredFont</span><span class="p">(</span><span class="n">forTextStyle</span><span class="p">:</span> <span class="p">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">label</span><span class="p">.</span><span class="n">adjustsFontForContentSizeCategory</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">label</span>
</span></span><span class="line"><span class="cl"><span class="p">}()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">private</span> <span class="kr">lazy</span> <span class="kd">var</span> <span class="nv">button</span><span class="p">:</span> <span class="n">UIButton</span> <span class="p">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">button</span> <span class="p">=</span> <span class="n">UIButton</span><span class="p">(</span><span class="n">type</span><span class="p">:</span> <span class="p">.</span><span class="n">system</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">button</span><span class="p">.</span><span class="n">setTitle</span><span class="p">(</span><span class="s">&#34;Action&#34;</span><span class="p">,</span> <span class="k">for</span><span class="p">:</span> <span class="p">.</span><span class="n">normal</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">button</span><span class="p">.</span><span class="n">titleLabel</span><span class="p">?.</span><span class="n">font</span> <span class="p">=</span> <span class="n">UIFont</span><span class="p">.</span><span class="n">preferredFont</span><span class="p">(</span><span class="n">forTextStyle</span><span class="p">:</span> <span class="p">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">button</span><span class="p">.</span><span class="n">titleLabel</span><span class="p">?.</span><span class="n">adjustsFontForContentSizeCategory</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">button</span>
</span></span><span class="line"><span class="cl"><span class="p">}()</span>
</span></span></code></pre></div><p>Right now, as we can see above, everything looks just fine. Both the label and button are fully visible. The problem appears when the user increases the font size in the system settings. We can easily emulate that using the simulator and the <code>⌥ ⌘ +</code> shortcut while the app is launched:</p>
<figure class="align-center ">
    <img loading="lazy" src="/uistackview/before.gif#center" width="300"/> 
</figure>

<p>When both elements don&rsquo;t fit horizontally, they are compressed more and more as we further increase the font size. Ultimately, the button&rsquo;s title disappears entirely, and we only see the three dots. Far from a good user experience, right?</p>
<p>Ideally, we would like to display the elements vertically when they no longer fit horizontally. Luckily, changing the axis of a <code>UIStackView</code> is trivial. It&rsquo;s enough to modify a single property (<code>stackView.axis = .vertical</code>).</p>
<p>But the challenge, however, is to trigger that change only when we detect that the label and button can&rsquo;t fit our screen horizontally without being compressed. Otherwise, we still want them to remain in the same configuration if there&rsquo;s enough space. Let&rsquo;s see how we can do that.</p>
<h2 id="solution">Solution</h2>
<p>The <code>UIView</code> contains a function we can override to solve our problem - <code>layoutSubviews</code>. The documentation says that</p>
<blockquote>
<p>Subclasses can override this method as needed to perform more precise layout of their subviews.</p>
</blockquote>
<p>In our case, a more precise layout is exactly what we need.</p>
<p>Generally, this function is called on a view every time layout changes occur. It includes situations like modifying the view&rsquo;s bounds, changing the interface orientation, calling <code>setNeedsLayout</code> or <code>layoutIfNeeded</code> on a view, etc.</p>
<p>This also implies that <code>layoutSubviews</code> is going to be called when the user increases the font size, which is exactly what we want.</p>
<p>Here&rsquo;s the code that we can put inside the <code>layoutSubviews</code> of our stack view&rsquo;s parent to solve our problem:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kr">override</span> <span class="kd">func</span> <span class="nf">layoutSubviews</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kc">super</span><span class="p">.</span><span class="n">layoutSubviews</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">maxWidth</span> <span class="p">=</span> <span class="n">bounds</span><span class="p">.</span><span class="n">width</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">labelWidth</span> <span class="p">=</span> <span class="n">label</span><span class="p">.</span><span class="n">sizeThatFits</span><span class="p">(</span><span class="n">frame</span><span class="p">.</span><span class="n">size</span><span class="p">).</span><span class="n">width</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">buttonWidth</span> <span class="p">=</span> <span class="n">button</span><span class="p">.</span><span class="n">sizeThatFits</span><span class="p">(</span><span class="n">frame</span><span class="p">.</span><span class="n">size</span><span class="p">).</span><span class="n">width</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">spacing</span> <span class="p">=</span> <span class="n">stackView</span><span class="p">.</span><span class="n">spacing</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">isHorizontal</span> <span class="p">=</span> <span class="n">maxWidth</span> <span class="o">&gt;</span> <span class="n">labelWidth</span> <span class="o">+</span> <span class="n">buttonWidth</span> <span class="o">+</span> <span class="n">spacing</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">stackView</span><span class="p">.</span><span class="n">axis</span> <span class="p">=</span> <span class="n">isHorizontal</span> <span class="p">?</span> <span class="p">.</span><span class="n">horizontal</span> <span class="p">:</span> <span class="p">.</span><span class="n">vertical</span>
</span></span><span class="line"><span class="cl">    <span class="n">stackView</span><span class="p">.</span><span class="n">alignment</span> <span class="p">=</span> <span class="n">isHorizontal</span> <span class="p">?</span> <span class="p">.</span><span class="n">firstBaseline</span> <span class="p">:</span> <span class="p">.</span><span class="n">leading</span>
</span></span><span class="line"><span class="cl">    <span class="n">stackView</span><span class="p">.</span><span class="n">invalidateIntrinsicContentSize</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>At first glance, the code might look complicated, so let&rsquo;s break it down.</p>
<p>Firstly, we determine whether the stack view should be horizontal or not. We do this by summing the widths of the label and button with the stack view&rsquo;s spacing.</p>
<p>If that sum is less than or equal to the width of the stack view&rsquo;s parent, it&rsquo;s safe to make the stack view horizontal because the elements would fit appropriately without being compressed. In other cases, the stack view should be vertical.</p>
<blockquote>
<p>We use <code>sizeThatFits</code> to calculate the size of a view. The documentation mentions that this method &ldquo;asks the view to calculate and return the size that best fits the specified size&rdquo;. In this case, we are passing the frame size of the stack view&rsquo;s parent.</p>
</blockquote>
<p>Additionally, we adjust the alignment so that in vertical mode, the elements are aligned to the leading edge of the screen and by first baseline in horizontal mode. Lastly, we call the <code>invalidateIntrinsicContentSize</code> to announce that the intrinsic size of our stack view has changed.</p>
<p>With those changes, we achieved the desired result:</p>
<figure class="align-center ">
    <img loading="lazy" src="/uistackview/after.gif#center" width="300"/> 
</figure>

<p>Initially, the elements are laid horizontally, same as before. Only when they would no longer fit entirely are they wrapped and displayed vertically.</p>
<h2 id="summary">Summary</h2>
<p>I hope the solution presented here will make it easier for you to make your app more accessible, which I believe is crucial. If you&rsquo;re interested, here&rsquo;s a <a href="https://gist.github.com/ClouddJR/76569dbc98f5179de6ff1cd3c453dc4c">link</a> to the entire source code of the application presented in this post.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to setup comments on your static blog</title>
      <link>https://arkadiuszchmura.com/posts/how-to-setup-comments-on-your-static-blog/</link>
      <pubDate>Tue, 30 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-setup-comments-on-your-static-blog/</guid>
      <description>With a tool called utterances, it&amp;rsquo;s very easy to add comments to your website with minimal code and no need for a database.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I&rsquo;ll show you how to setup comments on your static blog with a tool called <a href="https://utteranc.es/">utterances</a>. It&rsquo;s a lightweight, free, and open-source comments widget built on GitHub issues.</p>
<p>You can see what this tool looks like by scrolling to the bottom of the page where the comments section is.</p>
<p>The idea is simple. Every post on your blog will have a dedicated issue on your chosen GitHub repository. Then, every comment on your post will essentially become a comment on that issue. As a result, you won&rsquo;t need dedicated storage for these comments. Everything will be stored in your repository.</p>
<p>The only downside is that this way of adding comments requires users to have a GitHub account. If you have a technical blog or a website, that shouldn&rsquo;t be a problem since the majority of your audience is familiar with this tool. However, if that&rsquo;s not the case, you might want to look for something simpler.</p>
<p>My blog is built with <a href="https://gohugo.io/">Hugo</a> and a theme called <a href="https://github.com/reorx/hugo-PaperModX">PaperModX</a>, and that&rsquo;s what I&rsquo;ll be showing here. However, given how easy the integration is, you shouldn&rsquo;t have any problems with it when using different tools.</p>
<h2 id="integration">Integration</h2>
<p>Integration with utterances is relatively simple. You have to go to <a href="https://utteranc.es/">their website</a> and follow a couple of steps mentioned in the configuration section.</p>
<p>First, you choose a repository where you want to store your comments (and add the utterances app to it). Next, you select some options, like how you want to map your posts to issue titles or which theme you want to use on the widget. Lastly, you are given a code snippet containing a script tag that you have to add to your blog&rsquo;s template and position it where you want your comments to appear.</p>
<p>In the case of my blog, I had to add <code>comments: true</code> to my <code>config.yaml</code> file and then create the <code>layouts/partials/comments.html</code> file containing the generated script tag:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://utteranc.es/client.js&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">repo</span><span class="o">=</span><span class="s">&#34;ClouddJR/arkadiuszchmura.com&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">issue-term</span><span class="o">=</span><span class="s">&#34;pathname&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">label</span><span class="o">=</span><span class="s">&#34;comments&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">theme</span><span class="o">=</span><span class="s">&#34;github-light&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">async</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><blockquote>
<p>Notice how the options you selected in the configuration step match the attributes on the script tag.</p>
</blockquote>
<h3 id="dark-mode">Dark mode</h3>
<p>That&rsquo;s pretty much it when it comes to the integration. If you&rsquo;ve configured everything correctly, you should have a working system for adding comments to your website.</p>
<p>However, you might have noticed that my blog supports a dark mode that you can toggle by clicking on the icon at the top of the page. With the current configuration in the script tag, the theme used by the utterances widget will always be <code>github-light</code>, even when using dark mode on the website.</p>
<p>This definitely doesn&rsquo;t provide the best user experience, so I decided to find a way to set the correct initial theme when loading the page and also change the theme every time the user toggles it on the website.</p>
<p>This is the code that I ultimately used (I placed it right below the script tag for the utterances widget):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">updateUtterancesTheme</span><span class="p">(</span><span class="nx">isLight</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">iframe</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;.utterances-frame&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">iframe</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kr">const</span> <span class="nx">message</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;set-theme&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">theme</span><span class="o">:</span> <span class="nx">isLight</span> <span class="o">?</span> <span class="s1">&#39;github-light&#39;</span> <span class="o">:</span> <span class="s1">&#39;github-dark&#39;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nx">iframe</span><span class="p">.</span><span class="nx">contentWindow</span><span class="p">.</span><span class="nx">postMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="s1">&#39;https://utteranc.es&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The above is the function (credit goes to <a href="https://github.com/utterance/utterances/issues/549#issuecomment-907606127">this person</a>) for updating the theme used by the utterances widget. If the passed <code>isLight</code> variable is true, we&rsquo;ll use the <code>github-light</code> theme. Otherwise, it&rsquo;s going to be <code>github-dark</code>.</p>
<p>I wanted to execute this function as soon as the page loads and right before the utterances <code>iframe</code> makes a request. Here&rsquo;s one way of doing it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Set correct initial utterance theme
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">handleMessageEvent</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">origin</span> <span class="o">!==</span> <span class="s1">&#39;https://utteranc.es&#39;</span><span class="p">)</span> <span class="k">return</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">isLight</span> <span class="o">=</span> <span class="o">!</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">contains</span><span class="p">(</span><span class="s1">&#39;dark&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">updateUtterancesTheme</span><span class="p">(</span><span class="nx">isLight</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">removeEventListener</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="nx">handleMessageEvent</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="nx">handleMessageEvent</span><span class="p">)</span>
</span></span></code></pre></div><p>After these changes, the theme is set correctly after the page loads. The only thing left to do is to update the theme after toggling it using the icon at the top of the page.</p>
<p>Luckily, with PaperModX, it&rsquo;s quite easy to do. I just had to add the <code>updateUtterancesTheme</code> function to the array of callbacks that will be invoked every time the theme is changed, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Update utterances theme every time the theme is changed by a user
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">toggleThemeCallbacks</span><span class="p">[</span><span class="s1">&#39;comments&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nx">updateUtterancesTheme</span>
</span></span></code></pre></div><p>And that&rsquo;s all! If you want to get the whole picture and see all the changes in one place, <a href="https://github.com/ClouddJR/arkadiuszchmura.com/commit/191666a418713c4ae25fac9b2b1f6659429b84a4">here&rsquo;s the commit</a> on my blog&rsquo;s repository that introduced utterances. Also, feel free to explore the rest of the code.</p>
<h2 id="summary">Summary</h2>
<p>In this post, I showed you how easy it is to add comments to your blog or website without much effort using a really useful tool called utterances. Additionally, I presented a way of updating the theme used by the utterances widget so that you can correctly adjust it to a dark or light theme on your website. I hope you found that post helpful!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to make expandable text with a button in Jetpack Compose</title>
      <link>https://arkadiuszchmura.com/posts/how-to-make-expandable-text-with-a-button-in-jetpack-compose/</link>
      <pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-make-expandable-text-with-a-button-in-jetpack-compose/</guid>
      <description>In this post I will show you how to make an expandable text controlled by a button using Jetpack Compose.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I will show you how to make an expandable text that is controlled by a button below it using Jetpack Compose. Additionally, we&rsquo;ll introduce some simple animations to make the text state changes a bit nicer and add an ellipsis at the end of the text to indicate that it has overflowed.</p>
<p>That&rsquo;s the final result we&rsquo;ll be implementing:</p>
<figure class="align-center ">
    <img loading="lazy" src="/expandable/final.gif#center" width="350"/> 
</figure>

<h2 id="solution">Solution</h2>
<p>Let&rsquo;s start with the following snippet and build on top of it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">ComponentActivity</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">setContent</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">MyAppTheme</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Surface</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">fillMaxSize</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                    <span class="n">color</span> <span class="p">=</span> <span class="nc">MaterialTheme</span><span class="p">.</span><span class="n">colorScheme</span><span class="p">.</span><span class="n">background</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">ExpandableText</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">padding</span><span class="p">(</span><span class="m">16.</span><span class="n">dp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>You get that snippet after creating a new project using Android Studio’s project wizard. The only change I introduced is that I added the <code>ExpandableText</code> composable that we&rsquo;ll be building.</p>
<p>First, let&rsquo;s add a <code>Text</code> and <code>TextButton</code> composables (wrapped in a <code>Column</code>) inside our new <code>ExpandableText</code> composable:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">ExpandableText</span><span class="p">(</span><span class="n">modifier</span><span class="p">:</span> <span class="n">Modifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Column</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">modifier</span> <span class="p">=</span> <span class="n">modifier</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span> <span class="p">=</span> <span class="s2">&#34;Hello World! &#34;</span><span class="p">.</span><span class="n">repeat</span><span class="p">(</span><span class="m">50</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">maxLines</span> <span class="p">=</span> <span class="m">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">overflow</span> <span class="p">=</span> <span class="nc">TextOverflow</span><span class="p">.</span><span class="n">Ellipsis</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">TextButton</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">onClick</span> <span class="p">=</span> <span class="p">{</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">fillMaxWidth</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="n">shape</span> <span class="p">=</span> <span class="n">RectangleShape</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="n">text</span> <span class="p">=</span> <span class="s2">&#34;Expand&#34;</span><span class="p">.</span><span class="n">uppercase</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I am passing a modifier as a parameter to the <code>ExpandableText</code> to be able to control it from the outside.</p>
<p>Inside, I am setting the text to &ldquo;Hello World! &quot; repeated 50 times to make sure it overflows. Also, I&rsquo;m limiting the number of lines to 5 and passing <code>TextOverflow.Ellipsis</code> to the <code>overflow</code> parameter to use an ellipsis when the text overflows (by default, it just clips the text).</p>
<p>The <code>TextButton</code> below is set to fill the entire width and has a <code>RectangleShape</code> because it looks more appropriate in this case than the default, rounded shape.</p>
<p>This is what we have so far:</p>
<figure class="align-center ">
    <img loading="lazy" src="/expandable/overflow.png#center" width="350"/> 
</figure>

<p>Next, let&rsquo;s implement the <code>onClick</code> for our <code>TextButton</code>. When clicking, we want to remove the limit of 5 lines for the text (so that it expands) and change the text for the button from &ldquo;Expand&rdquo; to &ldquo;Collapse&rdquo;.</p>
<p>For that, we will introduce a mutable state variable called <code>isExpanded</code> that will be toggled inside the <code>onClick</code> and control the parameters mentioned above like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">ExpandableText</span><span class="p">(</span><span class="n">modifier</span><span class="p">:</span> <span class="n">Modifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">isExpanded</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">mutableStateOf</span><span class="p">(</span><span class="k">false</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">maxLines</span> <span class="p">=</span> <span class="k">if</span> <span class="p">(</span><span class="n">isExpanded</span><span class="p">)</span> <span class="nc">Int</span><span class="p">.</span><span class="n">MAX_VALUE</span> <span class="k">else</span> <span class="m">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">TextButton</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">onClick</span> <span class="p">=</span> <span class="p">{</span> <span class="n">isExpanded</span> <span class="p">=</span> <span class="o">!is</span><span class="n">Expanded</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span> <span class="p">=</span> <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="n">isExpanded</span><span class="p">)</span> <span class="s2">&#34;Collapse&#34;</span> <span class="k">else</span> <span class="s2">&#34;Expand&#34;</span><span class="p">).</span><span class="n">uppercase</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>After those changes, expanding and collapsing works properly:</p>
<figure class="align-center ">
    <img loading="lazy" src="/expandable/no_animation.gif#center" width="350"/> 
</figure>

<p>But there is one problem with our implementation. What happens when the text is shorter than 5 lines?</p>
<figure class="align-center ">
    <img loading="lazy" src="/expandable/short.png#center" width="350"/> 
</figure>

<p>We don&rsquo;t want to show the button when the text has not overflowed. To solve this, we need to find a way to be notified when the overflow happens and store it as a state.</p>
<p>Luckily, with Compose, it&rsquo;s easy to do. The <code>Text</code> composable exposes a <code>onTextLayout</code> parameter which is a callback that is executed when a new text layout is calculated. That callback will receive a <code>TextLayoutResult</code> object, from which we will be able to get all the necessary information:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">ExpandableText</span><span class="p">(</span><span class="n">modifier</span><span class="p">:</span> <span class="n">Modifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">textLayoutResult</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">mutableStateOf</span><span class="p">&lt;</span><span class="n">TextLayoutResult</span><span class="p">?&gt;(</span><span class="k">null</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">isExpandable</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">derivedStateOf</span> <span class="p">{</span> <span class="n">textLayoutResult</span><span class="o">?.</span><span class="n">didOverflowHeight</span> <span class="o">?:</span> <span class="k">false</span> <span class="p">}</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">onTextLayout</span> <span class="p">=</span> <span class="p">{</span> <span class="n">textLayoutResult</span> <span class="p">=</span> <span class="k">it</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We pass a lambda to the <code>onTextLayout</code> parameter, which will save a new <code>TextLayoutResult</code> object every time it changes into our <code>textLayoutResult</code> state.</p>
<p>Additionally, we define a derived state called <code>isExpandable</code> that will be recalculated every time the <code>textLayoutResult?.didOverflowHeight</code> changes. When it returns true, it means the text occupies more than 5 lines.</p>
<blockquote>
<p>We used derived state here because the <code>isExpandable</code> is never modified on its own. This state is always calculated based on the value of the <code>textLayoutResult</code> state. To learn more about derived states, <a href="https://developer.android.com/jetpack/compose/side-effects#derivedstateof">check the documentation</a>.</p>
</blockquote>
<p>Now, since we know when the text overflows, we can add another derived state that will control the visibility of the button:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">ExpandableText</span><span class="p">(</span><span class="n">modifier</span><span class="p">:</span> <span class="n">Modifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">isButtonShown</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">derivedStateOf</span> <span class="p">{</span> <span class="n">isExpandable</span> <span class="o">||</span> <span class="n">isExpanded</span> <span class="p">}</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">isButtonShown</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">TextButton</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This logic basically means that we only want to show the button when the text has overflowed (to be able to expand it) or when it&rsquo;s already expanded (to be able to collapse it).</p>
<p>Finally, the only thing that&rsquo;s missing is the animation, which we can add using a single modifier on our <code>Text</code> - <code>animateContentSize()</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">ExpandableText</span><span class="p">(</span><span class="n">modifier</span><span class="p">:</span> <span class="n">Modifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">animateContentSize</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And with that change, we get the desired effect after running the app!</p>
<p>Here&rsquo;s the full code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">ComponentActivity</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">setContent</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">ExpandableTextTheme</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Surface</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">fillMaxSize</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                    <span class="n">color</span> <span class="p">=</span> <span class="nc">MaterialTheme</span><span class="p">.</span><span class="n">colorScheme</span><span class="p">.</span><span class="n">background</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">ExpandableText</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">padding</span><span class="p">(</span><span class="m">16.</span><span class="n">dp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">ExpandableText</span><span class="p">(</span><span class="n">modifier</span><span class="p">:</span> <span class="n">Modifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">textLayoutResult</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">mutableStateOf</span><span class="p">&lt;</span><span class="n">TextLayoutResult</span><span class="p">?&gt;(</span><span class="k">null</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">isExpandable</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">derivedStateOf</span> <span class="p">{</span> <span class="n">textLayoutResult</span><span class="o">?.</span><span class="n">didOverflowHeight</span> <span class="o">?:</span> <span class="k">false</span> <span class="p">}</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">isExpanded</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">mutableStateOf</span><span class="p">(</span><span class="k">false</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">isButtonShown</span> <span class="k">by</span> <span class="n">remember</span> <span class="p">{</span> <span class="n">derivedStateOf</span> <span class="p">{</span> <span class="n">isExpandable</span> <span class="o">||</span> <span class="n">isExpanded</span> <span class="p">}</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">Column</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">modifier</span> <span class="p">=</span> <span class="n">modifier</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span> <span class="p">=</span> <span class="s2">&#34;Hello World! &#34;</span><span class="p">.</span><span class="n">repeat</span><span class="p">(</span><span class="m">50</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">animateContentSize</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="n">maxLines</span> <span class="p">=</span> <span class="k">if</span> <span class="p">(</span><span class="n">isExpanded</span><span class="p">)</span> <span class="nc">Int</span><span class="p">.</span><span class="n">MAX_VALUE</span> <span class="k">else</span> <span class="m">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">overflow</span> <span class="p">=</span> <span class="nc">TextOverflow</span><span class="p">.</span><span class="n">Ellipsis</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">onTextLayout</span> <span class="p">=</span> <span class="p">{</span> <span class="n">textLayoutResult</span> <span class="p">=</span> <span class="k">it</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">isButtonShown</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">TextButton</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="n">onClick</span> <span class="p">=</span> <span class="p">{</span> <span class="n">isExpanded</span> <span class="p">=</span> <span class="o">!is</span><span class="n">Expanded</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">fillMaxWidth</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                <span class="n">shape</span> <span class="p">=</span> <span class="n">RectangleShape</span>
</span></span><span class="line"><span class="cl">            <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">text</span> <span class="p">=</span> <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="n">isExpanded</span><span class="p">)</span> <span class="s2">&#34;Collapse&#34;</span> <span class="k">else</span> <span class="s2">&#34;Expand&#34;</span><span class="p">).</span><span class="n">uppercase</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="summary">Summary</h2>
<p>That&rsquo;s it for this post. I hope you found it helpful and learned something from it. If you have any questions, feel free to leave a comment here or reach out to me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to create factories for models with polymorphic relationships in Laravel</title>
      <link>https://arkadiuszchmura.com/posts/how-to-create-factories-for-models-with-polymorphic-relationships-in-laravel/</link>
      <pubDate>Wed, 29 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-create-factories-for-models-with-polymorphic-relationships-in-laravel/</guid>
      <description>Factories for these models are a bit trickier to implement than the standard ones.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I will show you how to create factories for models that have polymorphic relationships with other models in your app.</p>
<p>This post assumes that you are familiar with polymorphic relationships. If that&rsquo;s not true, head to <a href="https://laravel.com/docs/10.x/eloquent-relationships#polymorphic-relationships">the documentation</a> to learn more.</p>
<h2 id="solution">Solution</h2>
<p>As an example, let&rsquo;s consider an app where we allow users to rate games or movies. For that, we define two Eloquent models - <code>Game</code> and <code>Movie</code>. Additionally, to avoid repetition, we use a single <code>Rating</code> model for both entities.</p>
<p>A simplified database structure for our app could look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">games</span>
</span></span><span class="line"><span class="cl">    <span class="nx">id</span> <span class="o">-</span> <span class="nx">integer</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span> <span class="o">-</span> <span class="nx">string</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="nx">movies</span>
</span></span><span class="line"><span class="cl">    <span class="nx">id</span> <span class="o">-</span> <span class="nx">integer</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span> <span class="o">-</span> <span class="nx">string</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="nx">ratings</span>
</span></span><span class="line"><span class="cl">    <span class="nx">id</span> <span class="o">-</span> <span class="nx">integer</span>
</span></span><span class="line"><span class="cl">    <span class="nx">rating</span> <span class="o">-</span> <span class="nx">integer</span>
</span></span><span class="line"><span class="cl">    <span class="nx">rateable_id</span> <span class="o">-</span> <span class="nx">integer</span>
</span></span><span class="line"><span class="cl">    <span class="nx">rateable_type</span> <span class="o">-</span> <span class="nx">string</span>
</span></span></code></pre></div><p>Now, let&rsquo;s move on to factories. For both <code>Game</code> and <code>Movie</code>, it would be a simple, regular factory. Something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">GameFactory</span> <span class="k">extends</span> <span class="nx">Factory</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">definition</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="nx">fake</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">word</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I&rsquo;m only showing the code for the <code>GameFactory</code>, as the <code>MovieFactory</code> would look almost identical.</p>
<p>The factory for our <code>Rating</code> model is going to be a bit more complicated, and we could define it like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">RatingFactory</span> <span class="k">extends</span> <span class="nx">Factory</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">definition</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;rateable_id&#39;</span> <span class="o">=&gt;</span> <span class="nx">Game</span><span class="o">::</span><span class="na">factory</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;rateable_type&#39;</span> <span class="o">=&gt;</span> <span class="k">function</span> <span class="p">(</span><span class="k">array</span> <span class="nv">$attributes</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="nx">Game</span><span class="o">::</span><span class="na">find</span><span class="p">(</span><span class="nv">$attributes</span><span class="p">[</span><span class="s1">&#39;rateable_id&#39;</span><span class="p">])</span><span class="o">-&gt;</span><span class="na">getMorphClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It&rsquo;s a typical pattern to assign a new factory instance to the foreign key of the relationship (hence the <code>'rateable_id' =&gt; Game::factory()</code>). Thanks to this, when we create a new <code>Rating</code> using the factory, a new <code>Game</code> instance will be automatically created for us.</p>
<p>The <code>rateable_type</code> attribute is more interesting. Potentially, we could hardcode the value to <code>App\Models\Game</code>, and it would work just fine because, by default, Laravel uses the fully qualified class name to store the &ldquo;type&rdquo; of the related model. However, I like to decouple my app internals from the database and usually change these values.</p>
<p>To do that, you can use the following code (placed in the <code>boot</code> method of one of your service providers) to store simple strings as the &ldquo;type&rdquo; in the database:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">Relation</span><span class="o">::</span><span class="na">enforceMorphMap</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;App\Models\Game&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;movie&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;App\Models\Movie&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span></code></pre></div><p>But after that change, we must provide correct values to our <code>RatingFactory</code>. That&rsquo;s precisely why we we used the <code>getMorphClass()</code> on the model instance. It allows us to get the valid morph alias at runtime.</p>
<p>Also, we used a closure to access other attributes defined in the factory (in particular, the <code>rateable_id</code>) to find the newly created <code>Game</code> model on which we call the <code>getMorphClass()</code> method.</p>
<p>To use the factory and create a new <code>Rating</code>, we can now call <code>Rating::factory()-&gt;create()</code>.</p>
<p>Notice that when we use this factory, by default, it will associate the new <code>Rating</code> model with a new <code>Game</code>. What if we would like to use a <code>Movie</code> model instead (or any other that might be added in the future)?</p>
<p>To do that, we could leverage <a href="https://laravel.com/docs/10.x/eloquent-factories#factory-states">factory states</a>. We can define a method called <code>forMovie</code> in our factory that will only modify the <code>rateable_id</code> and <code>rateable_type</code> attributes accordingly (leaving the remaining ones untouched):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">function</span> <span class="nf">forMovie</span><span class="p">()</span><span class="o">:</span> <span class="nx">Factory</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">state</span><span class="p">(</span><span class="k">function</span> <span class="p">(</span><span class="k">array</span> <span class="nv">$attributes</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;rateable_id&#39;</span> <span class="o">=&gt;</span> <span class="nx">Movie</span><span class="o">::</span><span class="na">factory</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;rateable_type&#39;</span> <span class="o">=&gt;</span> <span class="k">function</span> <span class="p">(</span><span class="k">array</span> <span class="nv">$attributes</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="nx">Movie</span><span class="o">::</span><span class="na">find</span><span class="p">(</span><span class="nv">$attributes</span><span class="p">[</span><span class="s1">&#39;rateable_id&#39;</span><span class="p">])</span><span class="o">-&gt;</span><span class="na">getMorphClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Then, you can create a new <code>Rating</code> associated with a <code>Movie</code> by calling <code>Rating::factory()-&gt;forMovie()-&gt;create()</code>.</p>
<p>Similarly, you could define a separate method for any other model related to <code>Rating</code> that you might add in the future.</p>
<h2 id="summary">Summary</h2>
<p>In summary, creating factories for models with polymorphic relationships in Laravel can be a bit trickier than the standard ones. However, by following the steps outlined in this post, I hope you won&rsquo;t have any problems with that.</p>
<p>If you have any questions, feel free to leave a comment here or reach out to me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Inline functions in Kotlin</title>
      <link>https://arkadiuszchmura.com/posts/inline-functions-in-kotlin/</link>
      <pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/inline-functions-in-kotlin/</guid>
      <description>A comprehensive guide to inline functions, covering their purpose, practical examples, and tips for when to use or avoid them.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I would like to explain in detail what inline functions are and what problems they address. Additionally, I will present some practical examples and tips on when it&rsquo;s appropriate to use inline functions and when to avoid them.</p>
<p>Before we go any further, let&rsquo;s first understand what inline functions do. The general idea is simple. If you mark a function with the <code>inline</code> modifier, the compiler will copy the body of that function and paste it at every call site.</p>
<p>As a result, this code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Body of the foo() function&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">foo</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>after compilation will be ultimately equivalent to this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Body of the foo() function&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Body of the foo() function&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>What happened here is instead of calling <code>foo()</code>, the compiler copied its content and pasted it into the body of the <code>main()</code> function.</p>
<p>Now that we have a basic intuition for inline functions, we can move on to discuss their applications.</p>
<h2 id="overhead-of-lambdas-and-anonymous-functions">Overhead of lambdas and anonymous functions</h2>
<p>In Kotlin, functions are <a href="https://en.wikipedia.org/wiki/First-class_function">first-class citizens</a>. They can be stored in variables or data structures, used as arguments, or returned from other functions. However, this feature has an important implication. Functions in these scenarios are represented as objects, which impose certain runtime penalties.</p>
<p>Let&rsquo;s illustrate this with an example. Suppose we write a function called <code>takeUntil</code> (which is surprisingly not in the standard library) that would take all the elements from an iterable until a provided predicate is satisfied.</p>
<p>This is what it could look like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;</span> <span class="nf">Iterable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;.</span><span class="n">takeUntil</span><span class="p">(</span><span class="n">predicate</span><span class="p">:</span> <span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Boolean</span><span class="p">):</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">list</span> <span class="p">=</span> <span class="n">ArrayList</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>  
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">item</span> <span class="k">in</span> <span class="k">this</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">list</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">predicate</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>  
</span></span><span class="line"><span class="cl">            <span class="k">break</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">list</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We define it as an extension function and specify one argument, <code>predicate</code>, which is a function that will control when we stop taking elements.</p>
<blockquote>
<p>In Kotlin, functions that take other functions as parameters, or return a function, are called High-order functions.</p>
</blockquote>
<p>Let&rsquo;s see what the decompiled bytecode for this function looks like in Java:</p>
<blockquote>
<p>In IntelliJ (or Android Studio), you can get the decompiled bytecode by going to <code>Tools</code> &gt; <code>Kotlin</code> &gt; <code>Show Kotlin Bytecode</code> and then clicking <code>Decompile</code> button to get the Java code.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">List</span><span class="w"> </span><span class="nf">takeUntil</span><span class="p">(</span><span class="nd">@NotNull</span><span class="w"> </span><span class="n">Iterable</span><span class="w"> </span><span class="n">$this$takeUntil</span><span class="p">,</span><span class="w"> </span><span class="nd">@NotNull</span><span class="w"> </span><span class="n">Function1</span><span class="w"> </span><span class="n">predicate</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>Notice that our <code>predicate</code> argument has a special <code>Function1</code> type (this <code>1</code> in <code>Function1</code> corresponds to the number of arguments our lambda accepts), which confirms that lambdas are indeed represented as objects. We must provide an instance of the <code>Function1</code> interface every time we call the <code>takeUntil</code> function.</p>
<p>Now, let&rsquo;s write some code to test our new function and see how lambdas that we pass to the <code>takeUntil</code> function are converted to objects of the <code>Function1</code> type under the hood:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">numbers</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">7</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="n">println</span><span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="n">takeUntil</span> <span class="p">{</span> <span class="k">it</span> <span class="o">&gt;=</span> <span class="m">5</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>When executed, this code prints a correct result (a list of numbers from 1 to 5 included), but we&rsquo;re interested in something else here. Let&rsquo;s see the decompiled version of the code above:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">List</span><span class="w"> </span><span class="n">numbers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CollectionsKt</span><span class="p">.</span><span class="na">listOf</span><span class="p">(</span><span class="k">new</span><span class="w"> </span><span class="n">Integer</span><span class="o">[]</span><span class="p">{</span><span class="n">1</span><span class="p">,</span><span class="w"> </span><span class="n">2</span><span class="p">,</span><span class="w"> </span><span class="n">3</span><span class="p">,</span><span class="w"> </span><span class="n">4</span><span class="p">,</span><span class="w"> </span><span class="n">5</span><span class="p">,</span><span class="w"> </span><span class="n">6</span><span class="p">,</span><span class="w"> </span><span class="n">7</span><span class="p">});</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">List</span><span class="w"> </span><span class="n">var1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">takeUntil</span><span class="p">((</span><span class="n">Iterable</span><span class="p">)</span><span class="n">numbers</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">Function1</span><span class="p">)</span><span class="kc">null</span><span class="p">.</span><span class="na">INSTANCE</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p>As you can see, the <code>takeUntil</code> function takes a mysterious <code>(Function1)null.INSTANCE</code> object as an argument. Where does it come from?</p>
<p>Unfortunately, the generated <code>Function1</code> interface doesn&rsquo;t reflect in the decompiled Java code, so we must dive deeper - into the bytecode itself.</p>
<p>I will skip all the irrelevant code for our discussion and present only the interesting parts.</p>
<p>First, we can see a class created that implements the <code>Function1</code> interface.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">final</span><span class="w"> </span><span class="kd">class</span> <span class="nc">MainKt$main$1</span><span class="w"> </span><span class="kd">extends</span><span class="w"> </span><span class="n">kotlin</span><span class="o">/</span><span class="n">jvm</span><span class="o">/</span><span class="n">internal</span><span class="o">/</span><span class="n">Lambda</span><span class="w"> </span><span class="kd">implements</span><span class="w"> </span><span class="n">kotlin</span><span class="o">/</span><span class="n">jvm</span><span class="o">/</span><span class="n">functions</span><span class="o">/</span><span class="n">Function1</span><span class="w">
</span></span></span></code></pre></div><p>The bytecode for that class is equivalent to the lambda body that we&rsquo;ve passed to the <code>takeUntil</code> function.</p>
<p>Our <code>main()</code> function is represented like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="n">GETSTATIC</span> <span class="n">MainKt</span><span class="err">$</span><span class="n">main</span><span class="err">$</span><span class="m">1.</span><span class="n">INSTANCE</span> <span class="p">:</span> <span class="n">LMainKt</span><span class="err">$</span><span class="n">main</span><span class="err">$</span><span class="m">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CHECKCAST</span> <span class="n">kotlin</span><span class="p">/</span><span class="n">jvm</span><span class="p">/</span><span class="n">functions</span><span class="p">/</span><span class="n">Function1</span>
</span></span><span class="line"><span class="cl"><span class="n">INVOKESTATIC</span> <span class="nc">MainKt</span><span class="p">.</span><span class="n">takeUntil</span> <span class="p">(</span><span class="n">Ljava</span><span class="p">/</span><span class="n">lang</span><span class="p">/</span><span class="n">Iterable</span><span class="p">;</span><span class="n">Lkotlin</span><span class="p">/</span><span class="n">jvm</span><span class="p">/</span><span class="n">functions</span><span class="p">/</span><span class="n">Function1</span><span class="p">;)</span><span class="n">Ljava</span><span class="p">/</span><span class="n">util</span><span class="p">/</span><span class="n">List</span><span class="p">;</span>
</span></span></code></pre></div><p>The <code>GETSTATIC</code> <a href="https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions">instruction</a> gets a class&rsquo;s static field value, which means we get a singleton here that is ultimately passed to the <code>takeUntil</code> function.</p>
<p>Let&rsquo;s do a quick experiment to confirm that if we put our code in a loop that runs 1000 times, we still use that singleton, and we don&rsquo;t create 1000 new objects:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">numbers</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">7</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="n">repeat</span><span class="p">(</span><span class="m">1000</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">println</span><span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="n">takeUntil</span> <span class="p">{</span> <span class="k">it</span> <span class="o">&gt;=</span> <span class="m">5</span> <span class="p">})</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>After getting the bytecode, we can confirm that the <code>GETSTATIC</code> instruction is still used, so no new objects are being created.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="n">GETSTATIC</span> <span class="n">MainKt</span><span class="err">$</span><span class="n">main</span><span class="err">$</span><span class="m">1</span><span class="err">$</span><span class="m">1.</span><span class="n">INSTANCE</span> <span class="p">:</span> <span class="n">LMainKt</span><span class="err">$</span><span class="n">main</span><span class="err">$</span><span class="m">1</span><span class="err">$</span><span class="m">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CHECKCAST</span> <span class="n">kotlin</span><span class="p">/</span><span class="n">jvm</span><span class="p">/</span><span class="n">functions</span><span class="p">/</span><span class="n">Function1</span>
</span></span><span class="line"><span class="cl"><span class="n">INVOKESTATIC</span> <span class="nc">MainKt</span><span class="p">.</span><span class="n">takeUntil</span> <span class="p">(</span><span class="n">Ljava</span><span class="p">/</span><span class="n">lang</span><span class="p">/</span><span class="n">Iterable</span><span class="p">;</span><span class="n">Lkotlin</span><span class="p">/</span><span class="n">jvm</span><span class="p">/</span><span class="n">functions</span><span class="p">/</span><span class="n">Function1</span><span class="p">;)</span><span class="n">Ljava</span><span class="p">/</span><span class="n">util</span><span class="p">/</span><span class="n">List</span><span class="p">;</span>
</span></span></code></pre></div><p>So far, nothing dramatic. The bytecode contains an additional class implementing the <code>Function1</code> interface that represents our lambda passed to the <code>takeUntil</code> function. Additionally, a singleton was used, so there is only one instance of that class at runtime.</p>
<p>However, the situation is <strong>entirely different</strong> when we start capturing variables in lambdas.</p>
<p>Let&rsquo;s store the value we had in the lambda in a variable called <code>limit</code> and use it instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">limit</span> <span class="p">=</span> <span class="m">5</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="py">numbers</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">7</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">repeat</span><span class="p">(</span><span class="m">1000</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">println</span><span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="n">takeUntil</span> <span class="p">{</span> <span class="k">it</span> <span class="o">&gt;=</span> <span class="n">limit</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And here&rsquo;s the bytecode representation:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="n">INVOKESPECIAL</span> <span class="n">MainKt</span><span class="err">$</span><span class="n">main</span><span class="err">$</span><span class="m">1</span><span class="err">$</span><span class="m">1.</span><span class="p">&lt;</span><span class="k">init</span><span class="p">&gt;</span> <span class="p">(</span><span class="n">I</span><span class="p">)</span><span class="n">V</span>
</span></span><span class="line"><span class="cl"><span class="n">CHECKCAST</span> <span class="n">kotlin</span><span class="p">/</span><span class="n">jvm</span><span class="p">/</span><span class="n">functions</span><span class="p">/</span><span class="n">Function1</span>
</span></span><span class="line"><span class="cl"><span class="n">INVOKESTATIC</span> <span class="nc">MainKt</span><span class="p">.</span><span class="n">takeUntil</span> <span class="p">(</span><span class="n">Ljava</span><span class="p">/</span><span class="n">lang</span><span class="p">/</span><span class="n">Iterable</span><span class="p">;</span><span class="n">Lkotlin</span><span class="p">/</span><span class="n">jvm</span><span class="p">/</span><span class="n">functions</span><span class="p">/</span><span class="n">Function1</span><span class="p">;)</span><span class="n">Ljava</span><span class="p">/</span><span class="n">util</span><span class="p">/</span><span class="n">List</span><span class="p">;</span>
</span></span></code></pre></div><p>As you can see, there is no <code>GETSTATIC</code> instruction anymore. Instead, there is <code>INVOKESPECIAL</code> that calls <code>&lt;init&gt;</code>. This line means we are creating a new object of that class. Given that we run this code 1000 times, the same number of new objects will be created at this point.</p>
<p>It&rsquo;s worth remembering that when we create lambdas that capture closures, there will <strong>always</strong> be a new object created, as the above experiment proved. However, in most cases, that won&rsquo;t be a huge problem (unless you deal with a performance-critical application).</p>
<p>Regardless, the solution is to use inline functions. When we mark our <code>takeUntil</code> function as <code>inline</code>, this is the decompiled Java code that we get for the <code>main()</code> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">List</span><span class="w"> </span><span class="n">numbers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CollectionsKt</span><span class="p">.</span><span class="na">listOf</span><span class="p">(</span><span class="k">new</span><span class="w"> </span><span class="n">Integer</span><span class="o">[]</span><span class="p">{</span><span class="n">1</span><span class="p">,</span><span class="w"> </span><span class="n">2</span><span class="p">,</span><span class="w"> </span><span class="n">3</span><span class="p">,</span><span class="w"> </span><span class="n">4</span><span class="p">,</span><span class="w"> </span><span class="n">5</span><span class="p">,</span><span class="w"> </span><span class="n">6</span><span class="p">,</span><span class="w"> </span><span class="n">7</span><span class="p">});</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">int</span><span class="w"> </span><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">5</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">short</span><span class="w"> </span><span class="n">var2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">1000</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">var3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">var3</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">var2</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">var3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="kt">int</span><span class="w"> </span><span class="n">var5</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="n">Iterable</span><span class="w"> </span><span class="n">$this$takeUntil$iv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Iterable</span><span class="p">)</span><span class="n">numbers</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="kt">int</span><span class="w"> </span><span class="n">$i$f$takeUntil</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="n">ArrayList</span><span class="w"> </span><span class="n">list$iv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="p">();</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="n">Iterator</span><span class="w"> </span><span class="n">var9</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">$this$takeUntil$iv</span><span class="p">.</span><span class="na">iterator</span><span class="p">();</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="k">while</span><span class="p">(</span><span class="n">var9</span><span class="p">.</span><span class="na">hasNext</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="n">Object</span><span class="w"> </span><span class="n">item$iv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">var9</span><span class="p">.</span><span class="na">next</span><span class="p">();</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="n">list$iv</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">item$iv</span><span class="p">);</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="kt">int</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">((</span><span class="n">Number</span><span class="p">)</span><span class="n">item$iv</span><span class="p">).</span><span class="na">intValue</span><span class="p">();</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="kt">int</span><span class="w"> </span><span class="n">var12</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">it</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">limit</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="k">break</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="p">}</span><span class="w">   
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="n">List</span><span class="w"> </span><span class="n">var13</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">List</span><span class="p">)</span><span class="n">list$iv</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="n">var13</span><span class="p">);</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>The content of the <code>takeUntil</code> function has been copied (inlined) here. Our lambda is no longer represented as an object, so we avoid an additional overhead. Instead, it&rsquo;s been inlined into the if statement (<code>if (it &gt;= limit)</code>).</p>
<h2 id="better-control-flow">Better control flow</h2>
<p>Another benefit of using inline functions is introducing a better control flow.</p>
<p>Let&rsquo;s consider a function that is supposed to find a user with a given id or throw an error when there is no such user:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">getUser</span><span class="p">(</span><span class="n">users</span><span class="p">:</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;,</span> <span class="n">id</span><span class="p">:</span> <span class="n">String</span><span class="p">):</span> <span class="n">User</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">users</span><span class="p">.</span><span class="n">forEach</span> <span class="p">{</span> <span class="n">user</span> <span class="o">-&gt;</span>  
</span></span><span class="line"><span class="cl">        <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Inspecting user: </span><span class="si">$user</span><span class="s2">&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">user</span><span class="p">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">user</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="n">error</span><span class="p">(</span><span class="s2">&#34;User with id </span><span class="si">$id</span><span class="s2"> not found.&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We iterate over the list of users and check if the current user is the one we seek. If it is, we immediately return that user from our <code>getUser</code> function. If we reach the end of the list, we throw an error.</p>
<p>Notice that we use a <code>return</code> statement not inside the <code>getUsers</code> function but in a lambda passed to the <code>forEach</code>. This is only possible because the <code>forEach</code> function has been marked with the <code>inline</code> modifier.</p>
<blockquote>
<p>Such returns (located in a lambda, but exiting the enclosing function) are called <em>non-local</em> returns.</p>
</blockquote>
<p>If we write our own version of <code>forEach</code> that is not inlined and use it instead, returning from a lambda won&rsquo;t be possible:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="c1">// This is the same function as forEach, but without the inline modifier
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;</span> <span class="nf">Iterable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;.</span><span class="n">noInlineForEach</span><span class="p">(</span><span class="n">action</span><span class="p">:</span> <span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">element</span> <span class="k">in</span> <span class="k">this</span><span class="p">)</span> <span class="n">action</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">getUser</span><span class="p">(</span><span class="n">users</span><span class="p">:</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;,</span> <span class="n">id</span><span class="p">:</span> <span class="n">String</span><span class="p">):</span> <span class="n">User</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">users</span><span class="p">.</span><span class="n">noInlineForEach</span> <span class="p">{</span> <span class="n">user</span> <span class="o">-&gt;</span>  
</span></span><span class="line"><span class="cl">        <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Inspecting user: </span><span class="si">$user</span><span class="s2">&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">user</span><span class="p">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">user</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="n">error</span><span class="p">(</span><span class="s2">&#34;User with id </span><span class="si">$id</span><span class="s2"> not found.&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We are getting an error that says &ldquo;&lsquo;return&rsquo; is not allowed here&rdquo;.</p>
<p>The reason why returning with the regular <code>forEach</code> is possible is that when a lambda is inlined, it&rsquo;s clear that the <code>return</code> statement applies to the top-level function (<code>getUsers</code>) because there are no other function calls made or objects created.</p>
<h2 id="noinline">Noinline</h2>
<p>If you don&rsquo;t want all of the lambdas passed to an inline function to be inlined, you can use the <code>noinline</code> modifier.</p>
<p>Consider the following inline function <code>execute</code> that decides which API to call based on whether the user is part of an experiment or not:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">execute</span><span class="p">(</span>  
</span></span><span class="line"><span class="cl">    <span class="n">isPartOfExperiment</span><span class="p">:</span> <span class="p">(</span><span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Boolean</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="n">callOldApi</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="n">callNewApi</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span>  
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">val</span> <span class="py">callApi</span> <span class="p">=</span> <span class="k">if</span><span class="p">(</span><span class="n">isPartOfExperiment</span><span class="p">(</span><span class="n">user</span><span class="p">))</span> <span class="n">callNewApi</span> <span class="k">else</span> <span class="n">callOldApi</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>We want to store the correct lambda in a variable called <code>callApi</code> and call it later at some point, but that&rsquo;s not possible. We get the &ldquo;Illegal usage of inline-parameter&rdquo; error. We can&rsquo;t store inlined lambdas in variables (or pass them to other functions) because they aren&rsquo;t objects anymore.</p>
<p>To solve this, we can add <code>noinline</code> modifiers to two of our lambdas, and our code compiles successfully:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">execute</span><span class="p">(</span>  
</span></span><span class="line"><span class="cl">    <span class="n">isPartOfExperiment</span><span class="p">:</span> <span class="p">(</span><span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Boolean</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="k">noinline</span> <span class="n">callOldApi</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="k">noinline</span> <span class="n">callNewApi</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span>  
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">val</span> <span class="py">callApi</span> <span class="p">=</span> <span class="k">if</span><span class="p">(</span><span class="n">isPartOfExperiment</span><span class="p">(</span><span class="n">user</span><span class="p">))</span> <span class="n">callNewApi</span> <span class="k">else</span> <span class="n">callOldApi</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><h2 id="crossinline">Crossinline</h2>
<p>In some cases, we still want to get all the benefits of using inline functions but without giving the possibility to use a <code>return</code> statement inside lambdas passed as parameters.</p>
<p>To indicate that the lambda parameter of the inline function cannot use non-local returns, we can mark it with the <code>crossinline</code> modifier.</p>
<p>Take a look at our little helper <code>benchmark</code> function that allows us to measure the execution time of a lambda passed as a parameter:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">benchmark</span><span class="p">(</span><span class="n">run</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">):</span> <span class="n">Long</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">duration</span> <span class="p">=</span> <span class="n">measureTime</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">run</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">duration</span><span class="p">.</span><span class="n">inWholeMilliseconds</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now, for a little experiment, let&rsquo;s try to run the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">time</span> <span class="p">=</span> <span class="n">benchmark</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="n">print</span><span class="p">(</span><span class="n">time</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It compiles successfully because the <code>benchmark</code> function is marked with the <code>inline</code> modifier, and using non-local returns is possible in such cases.</p>
<p>If we run it, the console won&rsquo;t print anything. That&rsquo;s because the <code>return</code> statement returns not from the <code>benchmark</code> function but immediately from the <code>main()</code>, thus ending the program.</p>
<p>If we don&rsquo;t want to allow code like this, we can use the <code>crossinline</code> modifier, and the <code>main()</code> function won&rsquo;t even compile. We will get the &ldquo;&lsquo;return&rsquo; is not allowed here&rdquo; error:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">benchmark</span><span class="p">(</span><span class="k">crossinline</span> <span class="n">run</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">):</span> <span class="n">Long</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">duration</span> <span class="p">=</span> <span class="n">measureTime</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">run</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">duration</span><span class="p">.</span><span class="n">inWholeMilliseconds</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="reified-types">Reified types</h2>
<p>Imagine we want to write a function that will return the first item of a given type from a list. For example, we have a <code>listOf(1, 2, &quot;string&quot;, 3)</code> and would like to get the first string from that list.</p>
<p>Here&rsquo;s one approach to writing such a function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;</span> <span class="nf">List</span><span class="p">&lt;*&gt;.</span><span class="n">firstIsInstance</span><span class="p">(</span><span class="n">clazz</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;):</span> <span class="n">T</span><span class="p">?</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nd">@Suppress</span><span class="p">(</span><span class="s2">&#34;UNCHECKED_CAST&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">firstOrNull</span> <span class="p">{</span> <span class="n">clazz</span><span class="p">.</span><span class="n">isInstance</span><span class="p">(</span><span class="k">it</span><span class="p">)</span> <span class="p">}</span> <span class="k">as</span> <span class="n">T</span><span class="p">?</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And that&rsquo;s what the code to use this function could look like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">items</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="m">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">println</span><span class="p">(</span><span class="n">items</span><span class="p">.</span><span class="n">firstIsInstance</span><span class="p">(</span><span class="n">String</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">))</span>  
</span></span></code></pre></div><p>This code works, but it’s not pretty. We have to pass that not-so-beautiful <code>String::class.java</code> to the function.</p>
<p>Additionally, inside, we have to use a suppression mechanism and call the parameter <code>clazz</code>, because <code>class</code> is a reserved keyword. A lot of compromises.</p>
<p>As an alternative, we can rewrite the <code>firstIsInstance</code> function as an inline version and utilize <em>reified type parameters</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="p">&lt;</span><span class="k">reified</span> <span class="nc">T</span><span class="p">&gt;</span> <span class="nf">List</span><span class="p">&lt;*&gt;.</span><span class="n">firstIsInstance</span><span class="p">():</span> <span class="n">T</span><span class="p">?</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">firstOrNull</span> <span class="p">{</span> <span class="k">it</span> <span class="k">is</span> <span class="n">T</span> <span class="p">}</span> <span class="k">as</span> <span class="n">T</span><span class="p">?</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Marking the type parameter with the <code>reified</code> modifier makes it accessible inside the function. Also, because the function is inlined, we can use normal operators like <code>as</code> or <code>is</code>, without relying on reflection.</p>
<p>With that change, the client code looks much more elegant:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">items</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="m">3</span><span class="p">)</span>   
</span></span><span class="line"><span class="cl"><span class="n">println</span><span class="p">(</span><span class="n">items</span><span class="p">.</span><span class="n">firstIsInstance</span><span class="p">&lt;</span><span class="n">String</span><span class="p">&gt;())</span>
</span></span></code></pre></div><h2 id="avoiding-inline-functions">Avoiding inline functions</h2>
<p>So far, we&rsquo;ve discussed the benefits of using inline functions. However, it&rsquo;s also worth mentioning when it would be better to avoid them.</p>
<p>First, it doesn&rsquo;t make much sense to add the <code>inline</code> modifier to a function that doesn&rsquo;t have any lambdas as parameters because the performance gains are unlikely. The JVM already optimizes small functions and inline them automatically.</p>
<p>Furthermore, you can&rsquo;t use inline functions when hiding implementation details (public inline functions can&rsquo;t call private functions):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">inline</span> <span class="k">fun</span> <span class="nf">doSomething</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">doSomethingPrivately</span><span class="p">()</span> <span class="c1">// Won&#39;t compile.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">doSomethingPrivately</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Private function&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>After learning about the benefits of inline functions, it might be tempting to use them everywhere now but resist the temptation.</p>
<p>For example, inlining a large function could dramatically increase the size of the generated bytecode because it&rsquo;s copied to every call site. For similar reasons, it&rsquo;s better to avoid inlining recursive calls.</p>
<h2 id="summary">Summary</h2>
<p>This was quite a long post, but I hope you learned a lot from it. As much as I love the <a href="https://kotlinlang.org/docs/home.html">Kotlin documentation</a>, I think the section dedicated to inline functions could use some work. That was the main motivation behind the decision to cover inline functions extensively here, including some practical examples.</p>
<p>If you have any questions, feel free to leave a comment here or reach out to me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to fix the invalid JDK problem on Electric Eel</title>
      <link>https://arkadiuszchmura.com/posts/how-to-fix-the-invalid-jdk-problem-on-electric-eel/</link>
      <pubDate>Fri, 20 Jan 2023 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-fix-the-invalid-jdk-problem-on-electric-eel/</guid>
      <description>When updating Android Studio to Electric Eel, the location of the embedded JDK is changing.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>When updating your Android Studio to the newest Electric Eel version, the location of the embedded JDK is changed. In particular, it changes from:</p>
<p><code>/Applications/Android Studio.app/Contents/jre/Contents/Home</code></p>
<p>to</p>
<p><code>/Applications/Android Studio.app/Contents/jbr/Contents/Home</code></p>
<p>This might cause some problems with building your projects right after the update.</p>
<h2 id="solution">Solution</h2>
<p>First, make sure the JDK is correctly specified for your project. Go to <code>Preferences</code> -&gt; <code>Build, Execution, Deployment</code> -&gt; <code>Build Tools</code> -&gt; <code>Gradle</code> and set the Gradle JDK to the correct one (if it didn&rsquo;t happen automatically):</p>
<figure class="align-center ">
    <img loading="lazy" src="/jdk.png#center"
         alt="Specifying JDK location in Preferences"/> <figcaption>
            <p>Specifying JDK location in Preferences</p>
        </figcaption>
</figure>

<p>Additionally, if your <code>JAVA_HOME</code> environment variable still points to the old location (as it was in my case), you will also have to update it.</p>
<blockquote>
<p>You can verify it by running <code>echo $JAVA_HOME</code> in your terminal. If it points to a completely different location, that&rsquo;s fine, you don&rsquo;t have to change that. It means you are using different JDKs in Android Studio and your terminal. However, I recommend using the same JDK everywhere to avoid problems with cache or running multiple Gradle daemons.</p>
</blockquote>
<p>To update it, go to your <code>~/.zshrc</code> or <code>~/.bashrc</code> (or any other place where you define your variables) and make sure you have this line there:</p>
<p><code>export JAVA_HOME=&quot;/Applications/Android Studio.app/Contents/jbr/Contents/Home&quot;</code></p>
<h2 id="summary">Summary</h2>
<p>I hope this post helped you solve your problem. I wish the JDK location change had been signaled more clearly after the update so that we wouldn&rsquo;t have to spend time investigating all the issues ourselves.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Be careful when converting Flow to LiveData</title>
      <link>https://arkadiuszchmura.com/posts/be-careful-when-converting-flow-to-livedata/</link>
      <pubDate>Sat, 31 Dec 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/be-careful-when-converting-flow-to-livedata/</guid>
      <description>LiveData created this way will only emit data when it has active observers.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Recently, I&rsquo;ve been working on a codebase where I had to write a bridging code between a data layer using <code>Flows</code> and a UI layer that still relied on the state exposed as <code>LiveData</code>.</p>
<p>Luckily, there is a function in the <code>androidx.lifecycle</code> called <code>asLiveData()</code> that allows you to convert a <code>Flow</code> to a <code>LiveData</code> effortlessly. However, there is one caveat to keep in mind when using a <code>LiveData</code> created this way. It will only emit data when it has at least one active observer. If there is an update to the upstream flow and the <code>LiveData</code> is inactive, it will not have the latest value.</p>
<p>Let me show you a potential problem we might encounter, with an example below:</p>
<h2 id="example">Example</h2>
<p>We have a simple activity that keeps a reference to an AAC <code>ViewModel</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">AppCompatActivity</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">viewModel</span><span class="p">:</span> <span class="n">MainViewModel</span> <span class="k">by</span> <span class="n">viewModels</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="n">setContentView</span><span class="p">(</span><span class="nc">R</span><span class="p">.</span><span class="n">layout</span><span class="p">.</span><span class="n">activity_main</span><span class="p">)</span>    
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <code>MainViewModel</code> looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainViewModel</span> <span class="p">:</span> <span class="n">ViewModel</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">repository</span> <span class="p">=</span> <span class="n">Repository</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">state</span><span class="p">:</span> <span class="n">LiveData</span><span class="p">&lt;</span><span class="n">Int</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">asLiveData</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We have a reference to a repository that will act as our trivial data layer. The <code>ViewModel</code> also exposes a state as a <code>LiveData</code> object converted from a <code>StateFlow</code> kept inside the repository using the <code>asLiveData()</code> function mentioned before.</p>
<p>Here is what the repository looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Repository</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">_state</span> <span class="p">=</span> <span class="n">MutableStateFlow</span><span class="p">(-</span><span class="m">1</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">state</span><span class="p">:</span> <span class="n">StateFlow</span><span class="p">&lt;</span><span class="n">Int</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">_state</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">update</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">_state</span><span class="p">.</span><span class="n">emit</span><span class="p">(</span><span class="nc">Random</span><span class="p">.</span><span class="n">nextInt</span><span class="p">(</span><span class="n">until</span> <span class="p">=</span> <span class="m">1000</span><span class="p">))</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It&rsquo;s a simple class with a <code>StateFlow</code> wrapping an integer (that starts with an initial value of -1) that also has a method allowing clients to update the state with a new random number between 0 and 1000.</p>
<p>Let&rsquo;s imagine we want to schedule the update as soon as our activity is created. We could do this by creating a method inside the <code>MainViewModel</code> called <code>init()</code> that we would call inside the <code>onCreate()</code> of our activity:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="c1">// MainViewModel
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fun</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// update() is suspending, so we launch a new coroutine here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">viewModelScope</span><span class="p">.</span><span class="n">launch</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">repository</span><span class="p">.</span><span class="n">update</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// MainActivity
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="n">setContentView</span><span class="p">(</span><span class="nc">R</span><span class="p">.</span><span class="n">layout</span><span class="p">.</span><span class="n">activity_main</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="n">viewModel</span><span class="p">.</span><span class="k">init</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now, during the creation of our activity, a new coroutine will be launched that will eventually call <code>update()</code> on the repository, generating a random number and emitting it to the state.</p>
<p>Additionally, let&rsquo;s suppose that there is a requirement to send an analytical event containing the newly generated number in our <code>ViewModel</code>. We could write a <code>sendAnalyticalEvent()</code> method in our <code>ViewModel</code> that we will run right after calling the <code>update()</code> method on the repository:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="c1">// MainViewModel
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fun</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">viewModelScope</span><span class="p">.</span><span class="n">launch</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">repository</span><span class="p">.</span><span class="n">update</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">        <span class="n">sendAnalyticalEvent</span><span class="p">()</span> <span class="c1">// &lt;-- NEW
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">sendAnalyticalEvent</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// Typically, we would schedule a network request here  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">liveDataValue</span> <span class="p">=</span> <span class="n">state</span><span class="p">.</span><span class="k">value</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">flowValue</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">value</span>  
</span></span><span class="line"><span class="cl">    <span class="nc">Log</span><span class="p">.</span><span class="n">d</span><span class="p">(</span><span class="s2">&#34;Current number in LiveData&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">$liveDataValue</span><span class="s2">&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="nc">Log</span><span class="p">.</span><span class="n">d</span><span class="p">(</span><span class="s2">&#34;Current number in StateFlow&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">$flowValue</span><span class="s2">&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Inside this method, we would typically schedule a network request to our backend servers but in this case, let&rsquo;s see both values from the  <code>LiveData</code> and <code>Flow</code> in the Logcat instead:</p>
<figure class="align-center ">
    <img loading="lazy" src="/flowtolivedata/1.png#center" width="350"/> 
</figure>

<p>Now, that is quite unexpected. You could argue that the <code>LiveData</code> doesn&rsquo;t have the newest value because there wasn&rsquo;t enough time to collect it from the upstream flow, and you might be right. But in this case, not only does the <code>LiveData</code> contain an incorrect value, but it&rsquo;s null! And remember, the initial value of the state in the repository was -1. It can only mean one thing - our  <code>LiveData</code> didn&rsquo;t collect anything from the <code>StateFlow</code>.</p>
<p>The reason is that we haven&rsquo;t started observing the <code>LiveData</code> anywhere. Therefore, it&rsquo;s considered <strong>inactive</strong>. And, according to the documentation of the <code>asLiveData()</code> function, in this state, <code>LiveData</code> won&rsquo;t be collecting any values from the upstream flow:</p>
<blockquote>
<p>Creates a <code>LiveData</code> that has values collected from the origin <code>Flow</code>.</p>
<p>The upstream flow collection starts when the returned <code>LiveData</code> becomes active (<code>LiveData.onActive</code>). If the <code>LiveData</code> becomes inactive (<code>LiveData.onInactive</code>) while the flow has not completed, the flow collection will be cancelled after <code>timeoutInMs</code> milliseconds unless the <code>LiveData</code> becomes active again before that timeout (to gracefully handle cases like Activity rotation).</p>
</blockquote>
<p>Once we start observing the state in our activity (hence making the <code>LiveData</code> active), it will contain the correct (newest) value:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="c1">// MainActivity
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="n">setContentView</span><span class="p">(</span><span class="nc">R</span><span class="p">.</span><span class="n">layout</span><span class="p">.</span><span class="n">activity_main</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="n">viewModel</span><span class="p">.</span><span class="k">init</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="n">viewModel</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">observe</span><span class="p">(</span><span class="k">this</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// &lt;-- NEW  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nc">Log</span><span class="p">.</span><span class="n">d</span><span class="p">(</span><span class="s2">&#34;Current number in MainActivity&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">$it</span><span class="s2">&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And this is the output from the Logcat:</p>
<figure class="align-center ">
    <img loading="lazy" src="/flowtolivedata/2.png#center" width="350"/> 
</figure>

<p>In this example, we use <code>StateFlow</code>, but the same rules apply to <code>SharedFlow</code>. Furthermore, it would be even worse because any events sent to a <code>SharedFlow</code> while the <code>LiveData</code> is inactive would be permanently lost (<code>SharedFlow</code>, by default, doesn&rsquo;t replay any values to new subscribers).</p>
<h2 id="summary">Summary</h2>
<p>Keep in mind that <code>LiveData</code> converted from a <code>Flow</code> using the <code>asLiveData()</code> function will behave slightly differently than expected. It will emit data only when there are active observers. To me, this behavior makes sense because we generally wouldn&rsquo;t be interested in <code>LiveData</code> values if we didn&rsquo;t observe it anywhere.</p>
<p>Regardless, there might be some use cases when you want to access the current value of your <code>LiveData</code> in your <code>ViewModel</code> before you start observing it. After reading this post, I hope you won&rsquo;t be surprised when encountering seemingly incorrect values in such situations.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Managing dotfiles with GitHub</title>
      <link>https://arkadiuszchmura.com/posts/managing-dotfiles-with-github/</link>
      <pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/managing-dotfiles-with-github/</guid>
      <description>This post will describe how I store and manage my dotfiles in a repository on GitHub.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Imagine you spill a cup of coffee onto your laptop keyboard one day. The damage is permanent, and you desperately need a new machine.</p>
<p>Now, ask yourself a question. How long would it take to bring your new machine to the previous state? That includes all user settings, editors and shell configurations, installed apps, and more.</p>
<p>If the answer is &ldquo;a couple of days&rdquo;, or even worse, &ldquo;a couple of weeks&rdquo;, continue reading to find out what you can do about that.</p>
<p>This post will show you how and where I store all my configuration files (dotfiles) to make switching between many machines a breeze.</p>
<p>Even though it might be quite an investment of time initially to set everything up, it will undoubtedly pay off in the future.</p>
<h2 id="repository">Repository</h2>
<p>I keep all my dotfiles and initializing scripts in a <a href="https://github.com/ClouddJR/dotfiles">repository on GitHub</a>. Feel free to use it as a template and adjust it to your needs and preferences. I, for example, was inspired by Freek Van der Herten&rsquo;s <a href="https://github.com/freekmurze/dotfiles">repository</a>.</p>
<p>Every time I want to set up a new machine, I clone my repository and run these simple commands:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">chmod +x bootstrap
</span></span><span class="line"><span class="cl">./bootstrap
</span></span></code></pre></div><p>Then, I follow the instructions on the screen which will do the job for me:</p>
<figure class="align-center ">
    <img loading="lazy" src="/dotfiles/bootstrap.png#center"/> 
</figure>

<p>I usually go through all of these options sequentially when starting from scratch. Let&rsquo;s explain what each of them does:</p>
<h3 id="1-bootstrap-terminal">1. Bootstrap terminal</h3>
<p>As the name suggests, this step is responsible for bootstrapping my terminal, which includes:</p>
<ul>
<li><strong>Hiding the &ldquo;last login&rdquo; line when starting a new session.</strong></li>
<li><strong>Installing oh-my-zsh</strong>. My terminal of choice is <a href="https://iterm2.com/">iTerm2</a>. I&rsquo;m using the <a href="https://en.wikipedia.org/wiki/Z_shell">Z shell</a> with <a href="https://ohmyz.sh/">oh-my-zsh</a>. It has a lot of valuable functions, plugins, helpers, and more. I highly recommend this combination.</li>
<li><strong>Creating symbolic links for .zsrhc and .vimrc</strong>. The latter contains a basic configuration for Vim. The former stores all the exports, aliases, and functions I frequently use when working on the shell. It also configures the theme (<a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes#robbyrussell">robbyrussell</a>) and specifies used plugins (in my case: git, adb, macos, and laravel). Usually, plugins will give you auto-completion for specific commands and some useful aliases. Check out the <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins-Overview">Wiki</a> for a complete list of plugins for oh-my-zsh. For example, here&rsquo;s what the auto-completion looks like for the adb plugin. As you can see, I can also navigate between suggested options using arrows, which is very convenient:</li>
</ul>
<figure class="align-center ">
    <img loading="lazy" src="/dotfiles/adb.gif#center"/> 
</figure>

<p>Sometimes I want to export variables (or aliases and functions) that I wouldn&rsquo;t store in a public repository for security reasons. In that case, I can create a <code>.dotfiles-custom</code> folder that git does not track, and the <code>.zshrc</code> will also load everything from there.</p>
<ul>
<li><strong>Activating <a href="https://github.com/rupa/z/">z.sh</a></strong>. If you&rsquo;ve never used it before, do yourself a favor and try it. It&rsquo;s a tremendously helpful and popular bash script for quick navigation between visited directories on your file system. For example, if you want to <code>cd</code> into a deeply nested directory (like <code>Development/Mobile/Android/MyProject</code>), you don&rsquo;t have to specify the entire path. It&rsquo;s enough to type <code>z project</code> to get there immediately (provided you have visited this directory before so that the script could save it in local history). It also works for sibling directories, as you can see below:</li>
</ul>
<figure class="align-center ">
    <img loading="lazy" src="/dotfiles/z.gif#center"/> 
</figure>

<ul>
<li><strong>Installing and setting up Homebrew</strong>. This package manager probably needs no introduction for macOS users. This substep also includes installing packages I use on most computers, like git, python, java, node, mysql, etc.</li>
</ul>
<h3 id="2-install-applications">2. Install applications</h3>
<p>You might be surprised that you can install regular GUI applications for macOS (those that require downloading .dmg files and running the installer) without leaving the terminal. It&rsquo;s possible thanks to an extension to Homebrew called <a href="https://github.com/Homebrew/homebrew-cask">Homebrew Cask</a>. Installing an application is as easy as running a single command (provided it&rsquo;s available as a Cask):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">brew install --cask firefox
</span></span></code></pre></div><p>This setup&rsquo;s step is straightforward. It&rsquo;s responsible for installing some apps (listed <a href="https://github.com/ClouddJR/dotfiles/blob/main/apps.md">in the repository</a>) using the above method.</p>
<p>Some apps, like IDEs, have their own configurations, which might include custom keyboard shortcuts, formatting styles, etc. I also keep them <a href="https://github.com/ClouddJR/dotfiles/tree/main/configs">in my repository</a> (in most cases as zip files) to easily import these configs after installation.</p>
<h3 id="3-set-system-defaults-macos">3. Set system defaults (macOS)</h3>
<p>Here, the script specifies values for some system preferences, like disabling the sound effect on boot or showing all file extensions by default in Finder. There&rsquo;s no shortage of things you can do. To learn more and get some inspiration, here&rsquo;s a helpful website with some demos: <a href="https://macos-defaults.com">https://macos-defaults.com</a>.</p>
<h2 id="summary">Summary</h2>
<p>I hope I convinced you that it&rsquo;s worth setting up your dotfiles repository to have a single place where all your configurations lie. Thanks to that, switching between many machines will be a piece of cake.</p>
<p>If you have some tips that you would like to share with me regarding this topic, feel free to reach me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to draw content behind system bars in Jetpack Compose</title>
      <link>https://arkadiuszchmura.com/posts/how-to-draw-content-behind-system-bars-in-jetpack-compose/</link>
      <pubDate>Mon, 31 Oct 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-draw-content-behind-system-bars-in-jetpack-compose/</guid>
      <description>It&amp;rsquo;s a typical use case, but it&amp;rsquo;s hard to find a concrete example in the documentation.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I would like to show you how you can draw content behind the system bars (status bar or navigation bar) when building a UI using Jetpack Compose.</p>
<p>A typical use case (that will be the focus of this post) is when you have an app bar or a navigation bar in your app and want to lay them out behind the system bars to achieve an effect of connectedness between system UI components and your app.</p>
<p>It can give your app a more compelling and modern user experience that adheres to the <a href="https://m3.material.io/">Material 3 guidelines</a>.</p>
<h2 id="solution">Solution</h2>
<p>To illustrate all the necessary steps, we will start with a basic app that has a <code>CenterAlignedTopAppBar</code>, <code>NavigationBar</code>, and a <code>LazyColumn</code> containing some items.</p>
<p>I created the project using the  <code>Empty Compose Activity</code> template from the Android Studio&rsquo;s project wizard. The generated code will make the navigation bar black by default, while the status bar will use the primary color specified in the theme.</p>
<p>Here&rsquo;s what the app looks like:</p>
<figure class="align-center ">
    <img loading="lazy" src="/insets/before.gif#center" width="350"/> 
</figure>

<p>And here&rsquo;s the code (without any irrelevant parts). Firstly, <code>MainActivity</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">ComponentActivity</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">        <span class="n">setContent</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="n">App</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@OptIn</span><span class="p">(</span><span class="n">ExperimentalMaterial3Api</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">AppTheme</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">scrollBehavior</span> <span class="p">=</span> <span class="nc">TopAppBarDefaults</span><span class="p">.</span><span class="n">pinnedScrollBehavior</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">Scaffold</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">topBar</span> <span class="p">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">CenterAlignedTopAppBar</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">title</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Text</span><span class="p">(</span><span class="s2">&#34;Title&#34;</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">                    <span class="n">scrollBehavior</span> <span class="p">=</span> <span class="n">scrollBehavior</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="n">bottomBar</span> <span class="p">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">NavigationBar</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">NavigationBarItem</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">selected</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="n">icon</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Icon</span><span class="p">(</span><span class="n">imageVector</span> <span class="p">=</span> <span class="nc">Icons</span><span class="p">.</span><span class="nc">Default</span><span class="p">.</span><span class="n">Home</span><span class="p">,</span> <span class="n">contentDescription</span> <span class="p">=</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">                        <span class="n">label</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Text</span><span class="p">(</span><span class="s2">&#34;First&#34;</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">                        <span class="n">onClick</span> <span class="p">=</span> <span class="p">{</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="n">NavigationBarItem</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">selected</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="n">icon</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Icon</span><span class="p">(</span><span class="n">imageVector</span> <span class="p">=</span> <span class="nc">Icons</span><span class="p">.</span><span class="nc">Default</span><span class="p">.</span><span class="n">Face</span><span class="p">,</span> <span class="n">contentDescription</span> <span class="p">=</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">                        <span class="n">label</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Text</span><span class="p">(</span><span class="s2">&#34;Second&#34;</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">                        <span class="n">onClick</span> <span class="p">=</span> <span class="p">{</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span> <span class="p">{</span> <span class="n">paddingValues</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="n">Surface</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="n">modifier</span> <span class="p">=</span> <span class="n">Modifier</span>
</span></span><span class="line"><span class="cl">                    <span class="p">.</span><span class="n">padding</span><span class="p">(</span><span class="n">paddingValues</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="p">.</span><span class="n">fillMaxSize</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">LazyColumn</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">nestedScroll</span><span class="p">(</span><span class="n">scrollBehavior</span><span class="p">.</span><span class="n">nestedScrollConnection</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                    <span class="n">contentPadding</span> <span class="p">=</span> <span class="n">PaddingValues</span><span class="p">(</span><span class="m">16.</span><span class="n">dp</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                    <span class="n">verticalArrangement</span> <span class="p">=</span> <span class="nc">Arrangement</span><span class="p">.</span><span class="n">spacedBy</span><span class="p">(</span><span class="m">8.</span><span class="n">dp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">items</span><span class="p">(</span><span class="n">count</span> <span class="p">=</span> <span class="m">100</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="n">Text</span><span class="p">(</span><span class="s2">&#34;Hello Android!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And this is the body of the <code>AppTheme</code> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">AppTheme</span><span class="p">(</span>  
</span></span><span class="line"><span class="cl">    <span class="n">darkTheme</span><span class="p">:</span> <span class="n">Boolean</span> <span class="p">=</span> <span class="n">isSystemInDarkTheme</span><span class="p">(),</span>  
</span></span><span class="line"><span class="cl">    <span class="n">dynamicColor</span><span class="p">:</span> <span class="n">Boolean</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="n">content</span><span class="p">:</span> <span class="nd">@Composable</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span>  
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">colorScheme</span> <span class="p">=</span> <span class="k">when</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">dynamicColor</span> <span class="o">&amp;&amp;</span> <span class="nc">Build</span><span class="p">.</span><span class="nc">VERSION</span><span class="p">.</span><span class="n">SDK_INT</span> <span class="o">&gt;=</span> <span class="nc">Build</span><span class="p">.</span><span class="nc">VERSION_CODES</span><span class="p">.</span><span class="n">S</span> <span class="o">-&gt;</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="k">val</span> <span class="py">context</span> <span class="p">=</span> <span class="nc">LocalContext</span><span class="p">.</span><span class="n">current</span>  
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">darkTheme</span><span class="p">)</span> <span class="n">dynamicDarkColorScheme</span><span class="p">(</span><span class="n">context</span><span class="p">)</span> <span class="k">else</span> <span class="n">dynamicLightColorScheme</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">        <span class="n">darkTheme</span> <span class="o">-&gt;</span> <span class="n">DarkColorScheme</span>  
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="o">-&gt;</span> <span class="n">LightColorScheme</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">view</span> <span class="p">=</span> <span class="nc">LocalView</span><span class="p">.</span><span class="n">current</span>  
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(!</span><span class="n">view</span><span class="p">.</span><span class="n">isInEditMode</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">SideEffect</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="k">val</span> <span class="py">window</span> <span class="p">=</span> <span class="p">(</span><span class="n">view</span><span class="p">.</span><span class="n">context</span> <span class="k">as</span> <span class="n">Activity</span><span class="p">).</span><span class="n">window</span>  
</span></span><span class="line"><span class="cl">            <span class="n">window</span><span class="p">.</span><span class="n">statusBarColor</span> <span class="p">=</span> <span class="n">colorScheme</span><span class="p">.</span><span class="n">primary</span><span class="p">.</span><span class="n">toArgb</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">            <span class="nc">WindowCompat</span><span class="p">.</span><span class="n">getInsetsController</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">view</span><span class="p">).</span><span class="n">isAppearanceLightStatusBars</span> <span class="p">=</span> <span class="n">darkTheme</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="n">MaterialTheme</span><span class="p">(</span>  
</span></span><span class="line"><span class="cl">        <span class="n">colorScheme</span> <span class="p">=</span> <span class="n">colorScheme</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">        <span class="n">typography</span> <span class="p">=</span> <span class="n">Typography</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="p">=</span> <span class="n">content</span>  
</span></span><span class="line"><span class="cl">    <span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><blockquote>
<p>Notice the use of <code>val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()</code> at the beginning of the <code>App</code> composable. Thanks to this, we get that nice visual effect of elevation on the app bar when scrolling the list.</p>
<p>To utilize it, we first pass the created <code>scrollBehavior</code> to the <code>CenterAlignedTopAppBar</code>. Next, we attach its <code>nestedScrollConnection</code> to the <code>Modifier.nestedScroll</code> on the <code>LazyColumn</code> that will keep track of scroll events and notify the app bar about them.</p>
</blockquote>
<p>As you can see above, the user interface in our sample app is far from perfect. The black color of the navigation bar doesn&rsquo;t play nicely with our design. Also, no matter whether the app bar is elevated or not, the status bar has always the same color.</p>
<p>Ideally, we would like the system navigation bar to have the same color as our app&rsquo;s navigation bar. The same goes for the status bar. It should change colors based on the app bar&rsquo;s current elevation.</p>
<p>Here&rsquo;s the final effect that we would like to achieve:</p>
<figure class="align-center ">
    <img loading="lazy" src="/insets/after.gif#center" width="350"/> 
</figure>

<p>Luckily, it&rsquo;s not that complicated. There are only two steps we need to introduce to our code presented above:</p>
<ol>
<li>Laying out our app in full screen.</li>
<li>Changing the system bar colors and transparency.</li>
</ol>
<h3 id="laying-out-our-app-in-full-screen">Laying out our app in full screen</h3>
<p>A single line of code is enough to make sure our app goes edge-to-edge and is laid out using the entire width and height of the display (including the system bars). We can place it inside the <code>onCreate</code> method in our activity:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// This will lay out our app behind the system bars
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nc">WindowCompat</span><span class="p">.</span><span class="n">setDecorFitsSystemWindows</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="k">false</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="n">setContent</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">App</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="changing-the-system-bar-colors-and-transparency">Changing the system bar colors and transparency</h3>
<p>After drawing our content behind the system bars we need to make sure it&rsquo;s visible to the user. We can do that by setting the color of the navigation bar and the status bar to transparent.</p>
<blockquote>
<p>If you are interested, I wrote <a href="https://arkadiuszchmura.com/posts/how-to-change-system-bar-colors-in-compose/">an entire post</a> about changing the system bar colors in Compose.</p>
</blockquote>
<p>Here is the relevant part of the <code>AppTheme</code> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="n">SideEffect</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">window</span> <span class="p">=</span> <span class="p">(</span><span class="n">view</span><span class="p">.</span><span class="n">context</span> <span class="k">as</span> <span class="n">Activity</span><span class="p">).</span><span class="n">window</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="n">window</span><span class="p">.</span><span class="n">statusBarColor</span> <span class="p">=</span> <span class="nc">Color</span><span class="p">.</span><span class="nc">Transparent</span><span class="p">.</span><span class="n">toArgb</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="n">window</span><span class="p">.</span><span class="n">navigationBarColor</span> <span class="p">=</span> <span class="nc">Color</span><span class="p">.</span><span class="nc">Transparent</span><span class="p">.</span><span class="n">toArgb</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nc">Build</span><span class="p">.</span><span class="nc">VERSION</span><span class="p">.</span><span class="n">SDK_INT</span> <span class="o">&gt;=</span> <span class="nc">Build</span><span class="p">.</span><span class="nc">VERSION_CODES</span><span class="p">.</span><span class="n">Q</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">window</span><span class="p">.</span><span class="n">isNavigationBarContrastEnforced</span> <span class="p">=</span> <span class="k">false</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">windowsInsetsController</span> <span class="p">=</span> <span class="nc">WindowCompat</span><span class="p">.</span><span class="n">getInsetsController</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">view</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="n">windowsInsetsController</span><span class="p">.</span><span class="n">isAppearanceLightStatusBars</span> <span class="p">=</span> <span class="p">!</span><span class="n">darkTheme</span>  
</span></span><span class="line"><span class="cl">    <span class="n">windowsInsetsController</span><span class="p">.</span><span class="n">isAppearanceLightNavigationBars</span> <span class="p">=</span> <span class="p">!</span><span class="n">darkTheme</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Firstly, we set the system bar colors to transparent. Next, we tell the system not to enforce the navigation bar contrast, because by default, on API &gt;= 29, the system applies a translucent scrim behind the system bars. Lastly, we modify the icon colors to match the current theme (light or dark).</p>
<p>Now, after running the app, we get the desired effect and our app looks much better!</p>
<p>Notice that even though we draw our app bar and navigation bar behind the system bars, their content (titles, icons, etc.) doesn&rsquo;t interfere with the system bars. That&rsquo;s because since version <a href="https://developer.android.com/jetpack/androidx/releases/compose-material3#1.0.0-beta01"><code>1.0.0-beta01</code></a> of the <code>androidx.compose.material3:material3</code>, these components handle insets automatically and apply correct padding values based on them.</p>
<p>If we used previous versions, we would have to do it manually. If you are interested in how it used to be done, <a href="https://github.com/android/nowinandroid/commit/8c11769622d0684e76860e00db5dc1b797b5f731">here is the commit</a> from the <code>Now in Android</code> project that removes manual insets handling after bumping the library version.</p>
<h2 id="summary">Summary</h2>
<p>I hope this post will save you some time when you try to draw some UI components behind the system bars.</p>
<p>If you have any questions or comments, feel free to reach me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to test intermediate steps in suspending functions</title>
      <link>https://arkadiuszchmura.com/posts/how-to-test-intermediate-steps-in-suspending-functions/</link>
      <pubDate>Fri, 30 Sep 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-test-intermediate-steps-in-suspending-functions/</guid>
      <description>Testing the final result of a suspending function is easy, but what about verifying what happens inside it during the execution?</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Let&rsquo;s look at a simple suspending function that fetches some data from a server. Before executing a network call, it sets the <code>isLoading</code> variable to <code>true</code>. Then, after finishing successfully, it sets it back to <code>false</code> and returns the loaded data:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Repository</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">isLoading</span> <span class="p">=</span> <span class="k">false</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">fetchData</span><span class="p">():</span> <span class="n">String</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">isLoading</span> <span class="p">=</span> <span class="k">true</span>  
</span></span><span class="line"><span class="cl">        <span class="n">delay</span><span class="p">(</span><span class="m">500</span><span class="p">)</span> <span class="c1">// Simulate a network call  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">isLoading</span> <span class="p">=</span> <span class="k">false</span>  
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;Loaded data&#34;</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>For simplicity, let&rsquo;s ignore all the additional things we would normally take care of in a real project, like error handling, making the actual network call, parsing the result, etc. Instead, let&rsquo;s focus on the aspect of testing this snippet of code.</p>
<p>Testing the final result of the <code>fetchData</code> function is relatively easy with the help of some tools from the <code>kotlinx.coroutines.test</code> library. This is what such a test could look like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Test</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">`repository should return loaded data`</span><span class="p">()</span> <span class="p">=</span> <span class="n">runTest</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// given  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">val</span> <span class="py">repository</span> <span class="p">=</span> <span class="n">Repository</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1">// when  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">val</span> <span class="py">result</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="n">fetchData</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1">// then  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">assertEquals</span><span class="p">(</span><span class="s2">&#34;Loaded data&#34;</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><blockquote>
<p>Notice how this test doesn&rsquo;t look much different than what we would write if we were testing a regular function.</p>
</blockquote>
<p><code>runTest</code> is an extremely convenient function. It behaves similarly to <code>runBlocking</code>, with the difference that the code that it runs will skip delays. Thanks to this, we don&rsquo;t have to wait 500 ms (because of the <code>delay(500)</code> in our <code>fetchData</code> function) for the test to finish.</p>
<p>The code above works just fine, but what if we want to have more control over this test? We would like to make sure that the <code>fetchData</code> function indeed sets correct values to the <code>isLoading</code> variable - before and after making a network call.</p>
<h2 id="solution">Solution</h2>
<p>We can take advantage of the fact that <code>runTest</code> executes our test body in a new coroutine launched on a <code>TestScope</code>.</p>
<p>This scope uses a special kind of dispatcher - <code>StandardTestDispatcher</code>. Usually, dispatchers are used to control the thread on which our coroutines should run. This dispatcher does a bit more - it supports delay-skipping using a scheduler that operates on virtual time (<code>TestCoroutineScheduler</code>).</p>
<p>Coroutines started with the <code>StandardTestDispatcher</code> won&rsquo;t run immediately. Instead, the dispatcher always sends them to its scheduler. Then, it&rsquo;s our job to trigger their execution by controlling the virtual time. For this, we can use functions available on the <code>TestCoroutineScheduler</code>:  <code>advanceTimeBy</code>, <code>runCurrent</code> or <code>advanceUntilIdle</code>.</p>
<p>To see this in action, look at the code below:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Test</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">`child coroutine`</span><span class="p">()</span> <span class="p">=</span> <span class="n">runTest</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// 1  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">launch</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="c1">// 3  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// 2  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">advanceUntilIdle</span><span class="p">()</span> <span class="c1">// Run all the scheduled tasks
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// 4  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>When we call <code>launch</code>, the coroutine is not executed immediately. Instead, as mentioned earlier, it&rsquo;s sent to the scheduler. Only when we call <code>advanceUntilIdle</code> (or any other function controlling the virtual time), the child coroutine is executed.</p>
<blockquote>
<p>Notice that we can call <code>advanceUntilIdle</code> directly on the <code>TestScope</code>. It&rsquo;s because it&rsquo;s defined as an extension function that internally delegates the call to the scheduler. The same is true for the remaining functions modifying the virtual time.</p>
</blockquote>
<p>This behavior allows us to call the function we want to test inside a child coroutine. That coroutine will be sent to the scheduler and its execution is fully controllable by us.</p>
<p>We can advance the virtual time to the point where the data is about to be loaded and verify that the <code>isLoading</code> is properly set to <code>true</code>. Then we can run all the tasks scheduled at that time (remember the <code>delay(500)</code> that we had in our function?) by using <code>runCurrent</code>. Lastly, we can assert that the <code>isLoading</code> variable is back to <code>false</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Test</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">`repository should indicate that it&#39;s loading data`</span><span class="p">()</span> <span class="p">=</span> <span class="n">runTest</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// given  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">val</span> <span class="py">repository</span> <span class="p">=</span> <span class="n">Repository</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="n">launch</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">repository</span><span class="p">.</span><span class="n">fetchData</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1">// when  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">advanceTimeBy</span><span class="p">(</span><span class="m">500</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1">// then  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">assertTrue</span><span class="p">(</span><span class="n">repository</span><span class="p">.</span><span class="n">isLoading</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1">// when  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">runCurrent</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1">// then  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">assertFalse</span><span class="p">(</span><span class="n">repository</span><span class="p">.</span><span class="n">isLoading</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="regular-functions-that-launch-coroutines">Regular functions that launch coroutines</h2>
<p>Previously, we looked at testing intermediate steps in suspending functions. But in some cases, we want to test a regular, non-suspending function that launches a new coroutine inside. It&rsquo;s very common in many Android projects where you can see a code similar to this one:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TasksViewModel</span><span class="p">(</span><span class="k">private</span> <span class="k">val</span> <span class="py">repository</span><span class="p">:</span> <span class="n">TasksRepository</span><span class="p">)</span> <span class="p">:</span> <span class="n">ViewModel</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">_isLoading</span> <span class="p">=</span> <span class="n">MutableStateFlow</span><span class="p">(</span><span class="k">false</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">isLoading</span><span class="p">:</span> <span class="n">StateFlow</span><span class="p">&lt;</span><span class="n">Boolean</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">_isLoading</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">fun</span> <span class="nf">getTasks</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">viewModelScope</span><span class="p">.</span><span class="n">launch</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="n">_isLoading</span><span class="p">.</span><span class="n">emit</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">            <span class="n">repository</span><span class="p">.</span><span class="n">getTasks</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">            <span class="n">_isLoading</span><span class="p">.</span><span class="n">emit</span><span class="p">(</span><span class="k">false</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We have a <code>ViewModel</code> that exposes a function called <code>getTasks</code>. Internally, it launches a new coroutine using a <code>viewModelScope</code> in which it calls a suspending function <code>getTasks</code> from our repository. Besides, it correctly updates the <code>isLoading</code> state before and after.</p>
<p>Here&rsquo;s what the <code>TasksRepository</code> looks like (including the implementation that will be used in tests):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">interface</span> <span class="nc">TasksRepository</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">getTasks</span><span class="p">():</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&gt;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">InMemoryTasksRepository</span> <span class="p">:</span> <span class="n">TasksRepository</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">getTasks</span><span class="p">():</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&gt;</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">delay</span><span class="p">(</span><span class="m">500</span><span class="p">)</span> <span class="c1">// Simulate a network call  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">return</span> <span class="n">listOf</span><span class="p">(</span>  
</span></span><span class="line"><span class="cl">            <span class="n">Task</span><span class="p">(</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;Task 1&#34;</span><span class="p">),</span>  
</span></span><span class="line"><span class="cl">            <span class="n">Task</span><span class="p">(</span><span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;Task 2&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">        <span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Task</span><span class="p">(</span><span class="k">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="k">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span>
</span></span></code></pre></div><p>We can&rsquo;t directly use the same approach as previously, because the coroutine inside <code>getTasks</code> is launched on the <code>viewModelScope</code>. This scope knows nothing about the <code>TestScope</code> that is running our test body. This means that <code>viewModelScope.launch {...}</code> would be launched immediately instead of being scheduled by the <code>StandardTestDispatcher</code>.</p>
<p>To solve this, we need to force the <code>viewModelScope</code> to use the <code>StandardTestDispatcher</code> that we could control from the outside.</p>
<p>Luckily, according to the source code, <code>viewModelScope</code> is using a <code>Dispatchers.Main.immediate</code>. The main dispatcher can easily be replaced during tests using <code>Dispatchers.setMain</code>. There, we can pass our <code>StandardTestDispatcher</code>.</p>
<p>Here&rsquo;s how we could set up our test using the <code>@Before</code> and <code>@After</code> annotations:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">private</span> <span class="k">lateinit</span> <span class="k">var</span> <span class="py">testScheduler</span><span class="p">:</span> <span class="n">TestCoroutineScheduler</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@Before</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">testScheduler</span> <span class="p">=</span> <span class="n">TestCoroutineScheduler</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="nc">Dispatchers</span><span class="p">.</span><span class="n">setMain</span><span class="p">(</span><span class="n">StandardTestDispatcher</span><span class="p">(</span><span class="n">testScheduler</span><span class="p">))</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@After</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">tearDown</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nc">Dispatchers</span><span class="p">.</span><span class="n">resetMain</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span></code></pre></div><p>Before each test, we create a <code>StandardTestDispatcher</code>, providing our <code>TestCoroutineScheduler</code>, and set it as the main dispatcher (that we reset after each test).</p>
<p>Thanks to this, the <code>viewModelScope</code> will be using this dispatcher and all coroutines launched on this scope will be sent to our scheduler.</p>
<p>The code of our test will be almost identical to the previous one. The only difference is that we don&rsquo;t launch a child coroutine anymore and we control the virtual time by calling methods on the <code>testScheduler</code> variable.</p>
<p>Here is the full code of our test, including the setup:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ViewModelTest</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">lateinit</span> <span class="k">var</span> <span class="py">testScheduler</span><span class="p">:</span> <span class="n">TestCoroutineScheduler</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="nd">@Before</span>  
</span></span><span class="line"><span class="cl">    <span class="k">fun</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">testScheduler</span> <span class="p">=</span> <span class="n">TestCoroutineScheduler</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">        <span class="nc">Dispatchers</span><span class="p">.</span><span class="n">setMain</span><span class="p">(</span><span class="n">StandardTestDispatcher</span><span class="p">(</span><span class="n">testScheduler</span><span class="p">))</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="nd">@After</span>  
</span></span><span class="line"><span class="cl">    <span class="k">fun</span> <span class="nf">tearDown</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="nc">Dispatchers</span><span class="p">.</span><span class="n">resetMain</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="nd">@Test</span>  
</span></span><span class="line"><span class="cl">    <span class="k">fun</span> <span class="nf">`should indicate loading when getting the data`</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="c1">// given  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">val</span> <span class="py">viewModel</span> <span class="p">=</span> <span class="n">TasksViewModel</span><span class="p">(</span><span class="n">InMemoryTasksRepository</span><span class="p">())</span>  
</span></span><span class="line"><span class="cl">        <span class="n">viewModel</span><span class="p">.</span><span class="n">getTasks</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">        <span class="c1">// when  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">testScheduler</span><span class="p">.</span><span class="n">advanceTimeBy</span><span class="p">(</span><span class="m">500</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">        <span class="c1">// then  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">assertTrue</span><span class="p">(</span><span class="n">viewModel</span><span class="p">.</span><span class="n">isLoading</span><span class="p">.</span><span class="k">value</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">        <span class="c1">// when  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">testScheduler</span><span class="p">.</span><span class="n">runCurrent</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">        <span class="c1">// then  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">assertFalse</span><span class="p">(</span><span class="n">viewModel</span><span class="p">.</span><span class="n">isLoading</span><span class="p">.</span><span class="k">value</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Notice that we don&rsquo;t even have to run our test body inside <code>runTest</code> anymore. That&rsquo;s because we are not calling any suspending functions here - <code>getTasks</code> is a regular function.</p>
<h2 id="summary">Summary</h2>
<p>I hope this post showed you how we can easily make our tests more powerful and controllable when we write code that uses coroutines.</p>
<p>I first learned the trick of launching a child coroutine in a test to control it from the outside in a book I highly recommend - <a href="https://kt.academy/book/coroutines">Kotlin Coroutines: Deep Dive</a> by Marcin Moskala.</p>
<p>If you have any questions, feel free to reach me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What is the difference between size and viewport size in vector drawables?</title>
      <link>https://arkadiuszchmura.com/posts/what-is-the-difference-between-size-and-viewport-size-in-vector-drawables/</link>
      <pubDate>Wed, 31 Aug 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/what-is-the-difference-between-size-and-viewport-size-in-vector-drawables/</guid>
      <description>It always puzzled me so I decided to find out how are these things different.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>If like me, you have always wondered what is the difference between <code>viewportWidth</code> and <code>width</code> (or <code>viewportHeight</code> and <code>height</code>) in vector drawables and you tend to randomly tweak these attributes until your image looks right, this post is for you.</p>
<p>I will show you how these attributes differ using a simple example and some visualizations.</p>
<h2 id="example">Example</h2>
<p>To illustrate the difference, I created a simple app with one screen that contains a centered image filling as much content as it needs. Here is the code (in Jetpack Compose):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">ComponentActivity</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">setContent</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">AppTheme</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Box</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">modifier</span> <span class="p">=</span> <span class="nc">Modifier</span><span class="p">.</span><span class="n">fillMaxSize</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                    <span class="n">contentAlignment</span> <span class="p">=</span> <span class="nc">Alignment</span><span class="p">.</span><span class="n">Center</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">Image</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">painter</span> <span class="p">=</span> <span class="n">painterResource</span><span class="p">(</span><span class="n">id</span> <span class="p">=</span> <span class="nc">R</span><span class="p">.</span><span class="n">drawable</span><span class="p">.</span><span class="n">rectangle</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                        <span class="n">contentDescription</span> <span class="p">=</span> <span class="k">null</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And this is the code for the <code>R.drawable.rectangle</code> drawable:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34; encoding=&#34;utf-8&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;vector</span> <span class="na">xmlns:android=</span><span class="s">&#34;http://schemas.android.com/apk/res/android&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:width=</span><span class="s">&#34;256dp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:height=</span><span class="s">&#34;256dp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:viewportWidth=</span><span class="s">&#34;36&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:viewportHeight=</span><span class="s">&#34;36&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;path</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:fillColor=</span><span class="s">&#34;#FFEB3B&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:pathData=</span><span class="s">&#34;M0,0 L36,0 L36,36 L0,36 z&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;path</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:fillColor=</span><span class="s">&#34;#3F51B5&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:pathData=</span><span class="s">&#34;M2,2 L34,2 L34,34 L2,34 z&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/vector&gt;</span>
</span></span></code></pre></div><p>If you need a refresher on how to interpret commands like <code>M2,2</code> in <code>pathData</code>, here is a great post on Ray Wenderlich&rsquo;s blog: <a href="https://www.raywenderlich.com/3988300-vector-graphics-on-android">link</a>. But to give you a quick overview:</p>
<ul>
<li><code>M2,0</code> means <strong>M</strong>ove to the point at position 2,0 (x,y).</li>
<li><code>L36,0</code> means draw a <strong>L</strong>ine from the current point to the point at 36,0 (x,y).</li>
<li><code>z</code> closes the path by drawing a straight line from the current position to the starting point.</li>
</ul>
<blockquote>
<p>Remember that 0,0 position is in the upper left corner. Moving to the right increases the X position and moving down increases the Y position (contrary to what you might be used to).</p>
</blockquote>
<p>Both paths in the drawable above define a rectangle. The first path draws a yellow rectangle that covers the entire available space, while the second path draws a slightly smaller blue rectangle on top of the first one.</p>
<p>This is what the rendered image looks like:</p>
<figure class="align-center ">
    <img loading="lazy" src="/viewport/first.png#center" width="350"/> 
</figure>

<p>As you can see, <code>height</code> and <code>width</code> attributes were both set to &ldquo;256dp&rdquo; and <code>viewportWidth</code>, as well as <code>viewportHeight</code>, to &ldquo;36&rdquo;.</p>
<p>Notice that <code>height</code> and <code>width</code>  values end with &ldquo;dp&rdquo;. It&rsquo;s because they define the <strong>intrinsic</strong> size of the drawable. In simpler words, if you give this drawable to an <code>ImageView</code> that covers as much space as it needs, that <code>ImageView</code> will have the exact same size as the drawable. That&rsquo;s why in the screenshot above, the rendered image has a size of 256dp x 256dp (just like <code>height</code> and <code>width</code> values).</p>
<p>Conversely, <code>viewportWidth</code> and <code>viewportHeight</code> define the <strong>canvas</strong> size upon which we draw our pixels. All of our commands in <code>pathData</code> use coordinates from this space.</p>
<p>Let&rsquo;s take a look at the <code>pathData</code> for our blue rectangle:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">android:pathData=&#34;M2,2 L34,2 L34,34 L2,34 z&#34;
</span></span></code></pre></div><p>As you can see, all commands here use points that are contained in a space defined by <code>viewportWidth</code> and <code>viewportHeight</code> (which is 36 x 36).</p>
<p>Below I marked some of the relevant coordinates:</p>
<figure class="align-center ">
    <img loading="lazy" src="/viewport/first-coordinates.png#center" width="350"/> 
</figure>

<p>Now let&rsquo;s see what happens when I change <code>viewportWidth</code> and <code>viewportHeight</code> to &ldquo;48&rdquo; (and modify the yellow rectangle&rsquo;s <code>pathData</code> to still cover the entire space as in the previous example).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34; encoding=&#34;utf-8&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;vector</span> <span class="na">xmlns:android=</span><span class="s">&#34;http://schemas.android.com/apk/res/android&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:width=</span><span class="s">&#34;256dp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:height=</span><span class="s">&#34;256dp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:viewportWidth=</span><span class="s">&#34;48&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">android:viewportHeight=</span><span class="s">&#34;48&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;path</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:fillColor=</span><span class="s">&#34;#FFEB3B&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:pathData=</span><span class="s">&#34;M0,0 L48,0 L48,48 L0,48 z&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;path</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:fillColor=</span><span class="s">&#34;#3F51B5&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">android:pathData=</span><span class="s">&#34;M2,2 L34,2 L34,34 L2,34 z&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/vector&gt;</span>
</span></span></code></pre></div><p>Here is the rendered result:</p>
<figure class="align-center ">
    <img loading="lazy" src="/viewport/second.png#center" width="350"/> 
</figure>

<p>The image takes <strong>the same</strong> amount of space on the screen as before, but the blue rectangle is now smaller. This is because the <code>width</code> and <code>height</code> values stayed the same (&ldquo;256dp&rdquo;), but the coordinate space has changed affecting all of our commands responsible for drawing our paths.</p>
<p>This can be better seen in the below image with highlighted points:</p>
<figure class="align-center ">
    <img loading="lazy" src="/viewport/second-coordinates.png#center" width="350"/> 
</figure>

<h2 id="summary">Summary</h2>
<p>To summarize, the difference between size and viewport size is that the former reports its values (<code>width</code> and <code>height</code>) to the outside world, whereas the latter defines an &ldquo;internal&rdquo; space that is the coordinate space of our <code>pathData</code>.</p>
<p>If you are given a vector drawable (or svg) from a designer, remember not to change <code>viewportWidth</code> and <code>viewportHeight</code> attributes. They define the size of the canvas and all <code>pathData</code> commands use this coordinate space. If you change them, your image might become distorted. Instead, if you want to manipulate the image&rsquo;s size, just use <code>width</code> and <code>height</code>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to change system bar colors using Jetpack Compose</title>
      <link>https://arkadiuszchmura.com/posts/how-to-change-system-bar-colors-in-compose/</link>
      <pubDate>Wed, 20 Jul 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-change-system-bar-colors-in-compose/</guid>
      <description>System bar colors can be changed directly with Compose, without a need to modify any XML files.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I would like to show you how you can change the status bar and navigation bar colors using Compose, without having to modify any XML files.</p>
<p>Before Jetpack Compose, to specify the bar colors, we would traditionally modify the <code>themes.xml</code> file like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;resources&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&#34;Theme.BarColors&#34;</span> <span class="na">parent=</span><span class="s">&#34;android:Theme.Material.Light.NoActionBar&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&#34;android:statusBarColor&#34;</span><span class="nt">&gt;</span>@color/purple_700<span class="nt">&lt;/item&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&#34;android:navigationBarColor&#34;</span><span class="nt">&gt;</span>@color/purple_700<span class="nt">&lt;/item&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/style&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/resources&gt;</span>
</span></span></code></pre></div><p>As you can guess, the <code>android:statusBarColor</code> and <code>android:navigationBarColor</code> attributes affect the status bar color and navigation bar color, respectively.</p>
<p>Additionally, we could specify <code>android:windowLightStatusBar</code> (to make the icons on the status bar dark) or <code>android:windowLightNavigationBar</code> (similarly for navigation bar). Unfortunately, the latter requires API level 27. It forces us to override this attribute in another <code>themes.xml</code> file under the <code>values-27</code> folder. It can lead to quite a messy structure when we have a lot of attributes like this. It can get even worse when we decide to support a dark theme.</p>
<p>Luckily, with Compose, there is another way of doing this.</p>
<h2 id="solution">Solution</h2>
<p>For this example, I created a simple screen using Compose that displays centered text on a <code>Surface</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">ComponentActivity</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">?)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">super</span><span class="p">.</span><span class="n">onCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">        <span class="n">setContent</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">BarColorsTheme</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Surface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">Text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">modifier</span> <span class="p">=</span> <span class="n">Modifier</span>
</span></span><span class="line"><span class="cl">                            <span class="p">.</span><span class="n">fillMaxSize</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                            <span class="p">.</span><span class="n">wrapContentHeight</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                        <span class="n">textAlign</span> <span class="p">=</span> <span class="nc">TextAlign</span><span class="p">.</span><span class="n">Center</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="n">style</span> <span class="p">=</span> <span class="nc">MaterialTheme</span><span class="p">.</span><span class="n">typography</span><span class="p">.</span><span class="n">h3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="n">text</span> <span class="p">=</span> <span class="s2">&#34;Hello Android!&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <code>BarColorsTheme</code> (where <code>BarColors</code> is the name of the app) that wraps everything is a composable function that is created for you when you use the <code>Empty Compose Activity</code> template from the project wizard:</p>
<figure class="align-center ">
    <img loading="lazy" src="/compose-wizard.png#center"
         alt="Android Studio&rsquo;s new project wizard"/> <figcaption>
            <p>Android Studio&rsquo;s new project wizard</p>
        </figcaption>
</figure>

<p>This is what it looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">private</span> <span class="k">val</span> <span class="py">DarkColorPalette</span> <span class="p">=</span> <span class="n">darkColors</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">primary</span> <span class="p">=</span> <span class="n">Purple200</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">primaryVariant</span> <span class="p">=</span> <span class="n">Purple700</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">secondary</span> <span class="p">=</span> <span class="n">Teal200</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">private</span> <span class="k">val</span> <span class="py">LightColorPalette</span> <span class="p">=</span> <span class="n">lightColors</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">primary</span> <span class="p">=</span> <span class="n">Purple500</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">primaryVariant</span> <span class="p">=</span> <span class="n">Purple700</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">secondary</span> <span class="p">=</span> <span class="n">Teal200</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@Composable</span>
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">BarColorsTheme</span><span class="p">(</span><span class="n">darkTheme</span><span class="p">:</span> <span class="n">Boolean</span> <span class="p">=</span> <span class="n">isSystemInDarkTheme</span><span class="p">(),</span> <span class="n">content</span><span class="p">:</span> <span class="nd">@Composable</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">colors</span> <span class="p">=</span> <span class="k">if</span> <span class="p">(</span><span class="n">darkTheme</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">DarkColorPalette</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">LightColorPalette</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">MaterialTheme</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">colors</span> <span class="p">=</span> <span class="n">colors</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">typography</span> <span class="p">=</span> <span class="n">Typography</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">shapes</span> <span class="p">=</span> <span class="n">Shapes</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="p">=</span> <span class="n">content</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <code>BarColorsTheme</code> serves as a root composable that specifies the proper color palette (based on whether the dark theme is enabled), typography, and shapes for the entire hierarchy.</p>
<p>Because it is a root composable in our app, we can use this place to specify the system bar colors. Here is how we can do that:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nd">@Composable</span>  
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">BarColorsTheme</span><span class="p">(</span><span class="n">darkTheme</span><span class="p">:</span> <span class="n">Boolean</span> <span class="p">=</span> <span class="n">isSystemInDarkTheme</span><span class="p">(),</span> <span class="n">content</span><span class="p">:</span> <span class="nd">@Composable</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">val</span> <span class="py">view</span> <span class="p">=</span> <span class="nc">LocalView</span><span class="p">.</span><span class="n">current</span>  
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(!</span><span class="n">view</span><span class="p">.</span><span class="n">isInEditMode</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="n">SideEffect</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">            <span class="k">val</span> <span class="py">window</span> <span class="p">=</span> <span class="p">(</span><span class="n">view</span><span class="p">.</span><span class="n">context</span> <span class="k">as</span> <span class="n">Activity</span><span class="p">).</span><span class="n">window</span>  
</span></span><span class="line"><span class="cl">            <span class="n">window</span><span class="p">.</span><span class="n">statusBarColor</span> <span class="p">=</span> <span class="n">colors</span><span class="p">.</span><span class="n">primary</span><span class="p">.</span><span class="n">toArgb</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">            <span class="n">window</span><span class="p">.</span><span class="n">navigationBarColor</span> <span class="p">=</span> <span class="n">colors</span><span class="p">.</span><span class="n">primary</span><span class="p">.</span><span class="n">toArgb</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">            <span class="nc">WindowCompat</span><span class="p">.</span><span class="n">getInsetsController</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">view</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">                <span class="p">.</span><span class="n">isAppearanceLightStatusBars</span> <span class="p">=</span> <span class="n">darkTheme</span>  
</span></span><span class="line"><span class="cl">            <span class="nc">WindowCompat</span><span class="p">.</span><span class="n">getInsetsController</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">view</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">                <span class="p">.</span><span class="n">isAppearanceLightNavigationBars</span> <span class="p">=</span> <span class="n">darkTheme</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>We use the <code>window</code> object associated with our activity and modify the appropriate properties - <code>statusBarColor</code> and <code>navigationBarColor</code>. We use a primary color from the current palette (in this case it&rsquo;s a shade of purple).</p>
<p>Additionally, we use <code>WindowCompat</code> to make the status bar and navigation bar icons light or dark, depending on the value of the <code>darkTheme</code> variable. A nice benefit of using <code>WindowCompat</code> is that we don&rsquo;t have to check the API level before executing those methods. Behind the scenes, they will have no effect on unsupported APIs.</p>
<p>After making those changes and running the app, we get the desired effect:</p>
<figure class="align-center ">
    <img loading="lazy" src="/bar-colors-light.png#center"
         alt="System bar colors changed with Compose" width="350"/> <figcaption>
            <p>System bar colors changed with Compose</p>
        </figcaption>
</figure>

<p>Notice the use of <code>SideEffect</code> here. A <code>SideEffect</code> runs after <strong>every</strong> recomposition. Thanks to this, the system bar colors will be automatically updated to correct values when a user enables the dark theme, without having to reopen the app:</p>
<figure class="align-center ">
    <img loading="lazy" src="/bar-colors-change.gif#center"
         alt="System bar colors adapting to the current theme" width="350"/> <figcaption>
            <p>System bar colors adapting to the current theme</p>
        </figcaption>
</figure>

<h2 id="summary">Summary</h2>
<p>With Jetpack Compose, specifying system bar colors that adapt to the current theme is quite simple. All of the relevant code sits in one place. We no longer have to create different <code>themes.xml</code> files and override specific attributes.</p>
<p>I hope you found this post interesting. If you have any questions, feel free to reach me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How Twitter handled personalized timelines for their users</title>
      <link>https://arkadiuszchmura.com/posts/how-twitter-handled-personalized-timelines-for-their-users/</link>
      <pubDate>Tue, 28 Jun 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-twitter-handled-personalized-timelines-for-their-users/</guid>
      <description>The approach described here might be useful to you if your application has some sort of a personalized feed for each user.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I would like to write about an interesting concept I learned while reading <a href="https://dataintensive.net/">Designing Data-Intensive Applications</a> by Martin Kleppmann. More specifically, it&rsquo;s a story of how Twitter handled some of its scalability challenges related to users&rsquo; personalized timelines. If you work on an application with some sort of a personalized feed/timeline for each user, the idea introduced here might help you improve the performance or give you inspiration for your next app&rsquo;s architecture.</p>
<h2 id="scaling-timelines">Scaling timelines</h2>
<p>In November 2012, at a conference in San Francisco, Raffi Krikorian published some data about two of Twitter&rsquo;s main operations:</p>
<ul>
<li><strong>Post tweet</strong> - a user can post a new tweet to their followers (4,6k requests/sec on average, over 12k requests/sec at peak).</li>
<li><strong>Home timeline</strong> - a user can view tweets posted by the people they follow (300k requests/sec).</li>
</ul>
<p>With modern databases, handling 12,000 write requests is achievable fairly easily. But at Twitter, the challenge came not with the volume, but due to so-called <em>fan-out</em>. In transaction processing systems, this term is used to describe the number of requests to other services that need to be made to serve one incoming request. On Twitter, each user follows many people and each user is followed by many people. This means that when a new tweet is published, it needs to be delivered to all of the author&rsquo;s followers. In some cases (e.g. celebrities with many followers), there might be a lot of work to do.</p>
<p>On a high level, there are two ways of implementing the two operations mentioned above. Let&rsquo;s examine both of them.</p>
<h3 id="traditional-approach-with-relational-schema">Traditional approach with relational schema</h3>
<p>This is probably the first approach that comes to most developers&rsquo; minds. The idea is relatively simple. We need some kind of storage for all posted tweets. When a new tweet is posted, it&rsquo;s simply inserted into this global collection of tweets. When a user opens the website and requests their home timeline, all the tweets from all the people they follow are merged and served on demand. In a traditional relational database, you might have three tables to handle this scenario: users, tweets, and follows.</p>
<ul>
<li><em>users</em> table</li>
</ul>
<table>
  <thead>
      <tr>
          <th style="text-align: left">id</th>
          <th style="text-align: left">first_name</th>
          <th style="text-align: left">last_name</th>
          <th style="text-align: left">username</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">21</td>
          <td style="text-align: left">Arkadiusz</td>
          <td style="text-align: left">Chmura</td>
          <td style="text-align: left">ClouddJr</td>
      </tr>
  </tbody>
</table>
<ul>
<li><em>tweets</em> table</li>
</ul>
<table>
  <thead>
      <tr>
          <th style="text-align: left">id</th>
          <th style="text-align: left">user_id</th>
          <th style="text-align: left">content</th>
          <th style="text-align: left">created_at</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">14</td>
          <td style="text-align: left">21</td>
          <td style="text-align: left">Hello World!</td>
          <td style="text-align: left">2022-03-26 17:46:11</td>
      </tr>
  </tbody>
</table>
<ul>
<li><em>follows</em> table</li>
</ul>
<table>
  <thead>
      <tr>
          <th style="text-align: left">follower_id</th>
          <th style="text-align: left">followee_id</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">19212</td>
          <td style="text-align: left">21</td>
      </tr>
  </tbody>
</table>
<p>Then, to get all the relevant tweets to assemble a user&rsquo;s timeline, the SQL query could look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">tweets</span><span class="p">.</span><span class="o">*</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">users</span><span class="p">.</span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">tweets</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">JOIN</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">tweets</span><span class="p">.</span><span class="n">user_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">users</span><span class="p">.</span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">JOIN</span><span class="w"> </span><span class="n">follows</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">follows</span><span class="p">.</span><span class="n">followee_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">users</span><span class="p">.</span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">follows</span><span class="p">.</span><span class="n">follower_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">CURRENT_USER</span><span class="w">
</span></span></span></code></pre></div><p>The biggest problem here is that we have to execute the above query every time we want to display a timeline for any user. It&rsquo;s not hard to imagine the huge amount of work required when there are a lot of users on the platform with a substantial number of people they follow frequently accessing the website.</p>
<p>The first version of Twitter used this approach, but the system struggled to keep up with the load of home timeline queries. The number of users on the platform kept growing, so they had to introduce another solution.</p>
<h3 id="maintaining-a-cache-for-individual-timelines">Maintaining a cache for individual timelines</h3>
<p>Here, the basic idea is that we prepare, or <em>cache</em>, each user&rsquo;s home timeline ahead of time so that when it&rsquo;s requested, no additional work is required. When a user posts a tweet, besides being stored in a table, it&rsquo;s immediately inserted into timeline caches for all of their followers. Thanks to this, reading a timeline is very cheap, because it has already been computed - it&rsquo;s enough to just read from the cache. There is no need for any other expensive database operations. This concept is visualized in the image below.</p>
<figure class="align-center ">
    <img loading="lazy" src="/twitter-caches.png#center"
         alt="Twitter&rsquo;s data pipeline for delivering tweets to followers (2012)"/> <figcaption>
            <p>Twitter&rsquo;s data pipeline for delivering tweets to followers (2012)</p>
        </figcaption>
</figure>

<p>When it comes to actual tools that you could use to implement the timeline caching mechanism, a great option would be a very popular, open-source, in-memory data store called <a href="https://redis.io/"><code>Redis</code></a>.</p>
<p>However, while reading all relevant tweets for each user is very cheap right now, there is one downside of this approach. Posting a tweet now requires a lot of additional work. Besides storing it in a table, it has to be inserted into many other caches. The average number of followers per user is 75, which means 4,6k new tweets per second becomes 345k writes per second to the home timeline caches (4,6k * 75).</p>
<p>But the average is affected mainly by users with many followers (there are some with more than 30 million). The majority of users have much fewer followers. This means that the extra work required for the <em>fan-out</em> when posting a new tweet is only noticeable for that small number of users with a very large number of followers.</p>
<p>For this reason, Twitter moved to a hybrid approach to take the best of both worlds. Tweets from &ldquo;regular&rdquo; users continue to be <em>fanned-out</em> to timeline caches, as illustrated above, while tweets from celebrities are excepted from that process. When a home timeline is requested, tweets from celebrities are fetched separately from the database and merged with what&rsquo;s inside the user&rsquo;s cache.</p>
<h2 id="summary">Summary</h2>
<p>If you found this story interesting, you might enjoy reading the book it was mentioned in - Designing Data-Intensive Applications. It&rsquo;s a good combination of the theory behind many enterprise-level tools and practical engineering. It compares many tools and approaches, including their strengths and weaknesses, to make it easier for us to decide what&rsquo;s best for our applications.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to display responsive images from Laravel-medialibrary in Vue.js</title>
      <link>https://arkadiuszchmura.com/posts/how-to-display-responsive-image-from-laravel-medialibrary-in-vue-js/</link>
      <pubDate>Sun, 29 May 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-display-responsive-image-from-laravel-medialibrary-in-vue-js/</guid>
      <description>It&amp;rsquo;s easy to do in a Blade file, but what about a Vue component?</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p><a href="https://spatie.be/">Spatie</a> created an extremely useful library for working with any type of media in Laravel, called <a href="https://github.com/spatie/laravel-medialibrary"><code>Laravel-medialibrary</code></a>. It allows you to associate all sorts of files with Eloquent models and organize them into collections. It also has a simple fluent API that makes it effortless and pleasant to use.</p>
<p>Additionally, the package supports different filesystems (like Amazon S3) and can manipulate all uploaded images or pdfs according to the specified configuration. It&rsquo;s possible to resize, reformat, apply special effects, and much more. Check out the <a href="https://spatie.be/docs/laravel-medialibrary">documentation</a> to learn about everything it can do for you.</p>
<p>However, the feature I like most about this library is that it can automatically create responsive variants of images. The moment you upload an image, the media library will create resized versions of the original image suitable for different screen sizes, as well as a tiny blurred one used for progressive loading (which will be displayed before the full image is ready).</p>
<p>What&rsquo;s even better, the package has support for generating a necessary HTML markup, automatically creating an <code>img</code> tag and specifying <code>src</code>, <code>srcset</code>, and <code>sizes</code> attributes for you.</p>
<p>To display your image in a Blade file, all you have to do is output the <code>Media</code> object:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>My blog post<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{ $post-&gt;getFirstMedia() }}
</span></span></code></pre></div><p>It&rsquo;s very convenient, isn&rsquo;t it? But what about Vue? In a component&rsquo;s template, we can&rsquo;t just output the object like in a Blade file.</p>
<p>Luckily, there is a way to make responsive images work in Vue.</p>
<h2 id="solution">Solution</h2>
<p>The <code>Media</code> object implements the <code>Htmlable</code> interface, defined as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">interface</span> <span class="nx">Htmlable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Get content as a string of HTML.
</span></span></span><span class="line"><span class="cl"><span class="sd">     *
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return string
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">toHtml</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Internally, the Blade compiler will use the <code>toHtml()</code> method when it encounters a <code>Media</code> object while rendering the view.</p>
<p>This method is public, so nothing stops us from using it ourselves.</p>
<p>In a controller that&rsquo;s responsible for providing data used by your Vue component, simply return the result of the <code>toHtml()</code> method:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App\Http\Controllers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Http\Controllers\Controller</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PostController</span> <span class="k">extends</span> <span class="nx">Controller</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">show</span><span class="p">(</span><span class="nx">Post</span> <span class="nv">$post</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nv">$post</span><span class="o">-&gt;</span><span class="na">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;content&#39;</span> <span class="o">=&gt;</span> <span class="nv">$post</span><span class="o">-&gt;</span><span class="na">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;img&#39;</span> <span class="o">=&gt;</span> <span class="nv">$post</span><span class="o">-&gt;</span><span class="na">getFirstMedia</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">toHtml</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Then, inside your Vue component, output the image using the <code>v-html</code> directive by providing the data received from the controller:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-html</span><span class="o">=</span><span class="s">&#34;img&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>And that&rsquo;s it! Now, your image should be correctly displayed based on the screen size.</p>
<h2 id="summary">Summary</h2>
<p>If you&rsquo;ve been trying to take advantage of the simplicity of responsive images provided by the media library inside a Vue component, I hope this post saved you some time. If you have some questions, feel free to reach me on <a href="https://twitter.com/ClouddJR/">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How ViewModels survive configuration changes</title>
      <link>https://arkadiuszchmura.com/posts/how-viewmodels-survive-configuration-changes/</link>
      <pubDate>Tue, 26 Apr 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-viewmodels-survive-configuration-changes/</guid>
      <description>Let&amp;rsquo;s explore their implementation details to see how they achieve this.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>At Google I/O 2017, the Android Framework team introduced Architecture Components - a set of tools that significantly changed how many Android developers write and structure their apps. This post will focus on the internals of one of them - the <a href="https://developer.android.com/reference/androidx/lifecycle/ViewModel"><code>ViewModel</code></a>.</p>
<p>The <code>ViewModel</code> class is designed to store and manage UI-related data in a lifecycle conscious way. The <code>ViewModel</code> class allows data to <strong>survive configuration changes</strong> such as screen rotations.</p>
<p>Usually, one of the first things we find out when learning Android development is that activities get re-created after configuration changes. When it happens, we lose all initialized variables and the view gets re-rendered. We get a completely new activity instance.</p>
<p>So when I first heard about the <code>ViewModel</code> class and what it can do, some questions immediately popped up in my head:</p>
<ol>
<li>How is it possible that <code>ViewModels</code> survive configuration changes given that the activities that hold them get destroyed and created again?</li>
<li>How does the newly created activity instance access a reference to the same <code>ViewModel</code> used by the previous activity instance?</li>
</ol>
<p>Recently I decided to find answers to those questions. I chose to dive into the Android&rsquo;s source code and explore the <code>ViewModel</code>&rsquo;s implementation details.</p>
<h2 id="creating-a-viewmodel">Creating a ViewModel</h2>
<p>Let&rsquo;s start from the beginning. The recommended approach (at the time of writing this post) to create an instance of a <code>ViewModel</code> class inside an activity is to use the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">private</span> <span class="k">val</span> <span class="py">viewModel</span><span class="p">:</span> <span class="n">MyViewModel</span> <span class="k">by</span> <span class="n">viewModels</span><span class="p">()</span>
</span></span></code></pre></div><p>where <code>by viewModels()</code> is a syntax representing <a href="https://kotlinlang.org/docs/delegated-properties.html">Kotlin delegated properties</a>.</p>
<p>The <code>viewModels()</code> function returns a <code>Lazy&lt;T&gt;</code> instance, which serves as a lazy property delegate. This basically means that a <code>MyViewModel</code> instance is going to be obtained on first access to the <code>viewModel</code> variable (not when this variable is declared).</p>
<p>Here is what the <code>viewModels()</code> function looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">inline</span> <span class="k">fun</span> <span class="p">&lt;</span><span class="k">reified</span> <span class="nc">VM</span> <span class="p">:</span> <span class="nc">ViewModel</span><span class="p">&gt;</span> <span class="nf">ComponentActivity</span><span class="p">.</span><span class="n">viewModels</span><span class="p">(</span>  
</span></span><span class="line"><span class="cl">    <span class="k">noinline</span> <span class="n">factoryProducer</span><span class="p">:</span> <span class="p">(()</span> <span class="o">-&gt;</span> <span class="n">Factory</span><span class="p">)?</span> <span class="p">=</span> <span class="k">null</span>  
</span></span><span class="line"><span class="cl"><span class="p">):</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">VM</span><span class="p">&gt;</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">factoryPromise</span> <span class="p">=</span> <span class="n">factoryProducer</span> <span class="o">?:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">defaultViewModelProviderFactory</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ViewModelLazy</span><span class="p">(</span><span class="n">VM</span><span class="o">::</span><span class="k">class</span><span class="p">,</span> <span class="p">{</span> <span class="n">viewModelStore</span> <span class="p">},</span> <span class="n">factoryPromise</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It accepts a single parameter - a <code>factoryProducer</code>. If it&rsquo;s specified, the <code>ViewModelProvider.Factory</code> returned by this lambda will be used to create a <code>ViewModel</code> instance. If not, the default one will be used.</p>
<p>The function returns an instance of the <code>ViewModelLazy</code> class which is an implementation of the <code>Lazy</code> interface that I mentioned earlier.</p>
<p>The <code>ViewModelLazy</code>&rsquo;s constructor takes three parameters. The first one represents a class of the <code>ViewModel</code> we want to create an instance of. The third one is a lambda that returns a <code>ViewModelProvider.Factory</code>. It&rsquo;s the same one as the one passed to the <code>viewModels()</code> function (or a default one).</p>
<p>The second parameter is interesting. It&rsquo;s a lambda that returns a <code>ViewModelStore</code>. Here, a lambda is passed that returns a <code>viewModelStore</code> variable. Where is this variable coming from?</p>
<p>As you can see, the <code>viewModels()</code> function is an extension function on the <code>ComponentActivity</code> class. So when we call <code>viewModelStore</code> in Kotlin, we effectively invoke the <code>getViewModelStore()</code> method from the <code>ComponentActivity</code> (written in Java) that returns its member variable called <code>mViewModelStore</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="n">ViewModelStore</span><span class="w"> </span><span class="nf">getViewModelStore</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">getApplication</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">throw</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">IllegalStateException</span><span class="p">(</span><span class="s">&#34;Your activity is not yet attached to the &#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="o">+</span><span class="w"> </span><span class="s">&#34;Application instance. You can&#39;t request ViewModel before onCreate call.&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">ensureViewModelStore</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="n">mViewModelStore</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>The reason why the <code>ComponentActivity</code> has this method is that it implements the <code>ViewModelStoreOwner</code> interface. This is its declaration:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * A scope that owns {@link ViewModelStore}.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * &lt;p&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm"> * A responsibility of an implementation of this interface is to retain owned ViewModelStore
</span></span></span><span class="line"><span class="cl"><span class="cm"> * during the configuration changes and call {@link ViewModelStore#clear()}, when this scope is
</span></span></span><span class="line"><span class="cl"><span class="cm"> * going to be destroyed.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @see ViewTreeViewModelStoreOwner
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nd">@SuppressWarnings</span><span class="p">(</span><span class="s">&#34;WeakerAccess&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="kd">interface</span> <span class="nc">ViewModelStoreOwner</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">     * Returns owned {@link ViewModelStore}
</span></span></span><span class="line"><span class="cl"><span class="cm">     *
</span></span></span><span class="line"><span class="cl"><span class="cm">     * @return a {@code ViewModelStore}
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@NonNull</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">ViewModelStore</span><span class="w"> </span><span class="nf">getViewModelStore</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Now you may ask: &ldquo;What is <code>ViewModelStore</code>?&rdquo;</p>
<p>As the name suggests, the <code>ViewModelStore</code> class is responsible for <strong>storing</strong> instances of <code>ViewModels</code>. This is what this class looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">ViewModelStore</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">HashMap</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">ViewModel</span><span class="o">&gt;</span><span class="w"> </span><span class="n">mMap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashMap</span><span class="o">&lt;&gt;</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">final</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">put</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">ViewModel</span><span class="w"> </span><span class="n">viewModel</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">ViewModel</span><span class="w"> </span><span class="n">oldViewModel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mMap</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">viewModel</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">oldViewModel</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">oldViewModel</span><span class="p">.</span><span class="na">onCleared</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">final</span><span class="w"> </span><span class="n">ViewModel</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">key</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">mMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">key</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">Set</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span><span class="w"> </span><span class="nf">keys</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashSet</span><span class="o">&lt;&gt;</span><span class="p">(</span><span class="n">mMap</span><span class="p">.</span><span class="na">keySet</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">clear</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">ViewModel</span><span class="w"> </span><span class="n">vm</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">mMap</span><span class="p">.</span><span class="na">values</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">vm</span><span class="p">.</span><span class="na">clear</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">mMap</span><span class="p">.</span><span class="na">clear</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>This relatively simple class serves as a wrapper around <code>HashMap&lt;String, ViewModel&gt;</code>. This is the ultimate place where all <code>ViewModels</code> associated with an activity or a fragment are stored.</p>
<p>Now, since we know what the <code>ViewModelStore</code> is, it&rsquo;s clear what the <code>ViewModelStoreOwner</code> interface is used for. A class that implements it indicates to the outside world that it owns an instance of the <code>ViewModelStore</code>.</p>
<p>This is a list of all classes in the Android framework that implement the <code>getViewModelStore()</code> method from the <code>ViewModelStoreOwner</code> interface. Basically, it&rsquo;s only activities and fragments.</p>
<figure class="align-center ">
    <img loading="lazy" src="/getViewModelStore.png#center"
         alt="Classes that implement getViewModelStore() from the ViewModelStoreOwner"/> <figcaption>
            <p>Classes that implement <code>getViewModelStore()</code> from the <code>ViewModelStoreOwner</code></p>
        </figcaption>
</figure>

<p>Let&rsquo;s look at the documentation from the <code>ViewModelStoreOwner</code> interface, particularly this fragment:</p>
<blockquote>
<p>A responsibility of an implementation of this interface is to retain owned <code>ViewModelStore</code> during the configuration changes and call <code>ViewModelStore#clear()</code>, when this scope is going to be destroyed.</p>
</blockquote>
<p>This gives us a valuable hint. It means that it&rsquo;s the <strong>activity&rsquo;s (or fragment&rsquo;s) responsibility</strong> to make sure that its <code>ViewModelStore</code> (along with all <code>ViewModels</code>) is preserved across configuration changes.</p>
<p>How do activities handle that? We will come back to this question in the next section.</p>
<p>For now, let&rsquo;s go back again to the <code>viewModels()</code> function and see what the newly constructed <code>ViewModelLazy</code> class looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">class</span> <span class="nc">ViewModelLazy</span><span class="p">&lt;</span><span class="n">VM</span> <span class="p">:</span> <span class="n">ViewModel</span><span class="p">&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">viewModelClass</span><span class="p">:</span> <span class="n">KClass</span><span class="p">&lt;</span><span class="n">VM</span><span class="p">&gt;,</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">storeProducer</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="n">ViewModelStore</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">factoryProducer</span><span class="p">:</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="nc">ViewModelProvider</span><span class="p">.</span><span class="n">Factory</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">:</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">VM</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">var</span> <span class="py">cached</span><span class="p">:</span> <span class="n">VM</span><span class="p">?</span> <span class="p">=</span> <span class="k">null</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">value</span><span class="p">:</span> <span class="n">VM</span>
</span></span><span class="line"><span class="cl">        <span class="k">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">val</span> <span class="py">viewModel</span> <span class="p">=</span> <span class="n">cached</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">if</span> <span class="p">(</span><span class="n">viewModel</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">val</span> <span class="py">factory</span> <span class="p">=</span> <span class="n">factoryProducer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                <span class="k">val</span> <span class="py">store</span> <span class="p">=</span> <span class="n">storeProducer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                <span class="n">ViewModelProvider</span><span class="p">(</span><span class="n">store</span><span class="p">,</span> <span class="n">factory</span><span class="p">).</span><span class="k">get</span><span class="p">(</span><span class="n">viewModelClass</span><span class="p">.</span><span class="n">java</span><span class="p">).</span><span class="n">also</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">cached</span> <span class="p">=</span> <span class="k">it</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">viewModel</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">isInitialized</span><span class="p">():</span> <span class="n">Boolean</span> <span class="p">=</span> <span class="n">cached</span> <span class="o">!=</span> <span class="k">null</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Most of the code in this class just deals with caching the object and making sure that the same instance is returned on subsequent calls.</p>
<p>The most relevant fragment is this one:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="n">ViewModelProvider</span><span class="p">(</span><span class="n">store</span><span class="p">,</span> <span class="n">factory</span><span class="p">).</span><span class="k">get</span><span class="p">(</span><span class="n">viewModelClass</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
</span></span></code></pre></div><p>It creates an instance of the <code>ViewModelProvider</code> class by passing the required parameters (that were created by executing the lambdas passed to the constructor) and calls <code>get()</code> to obtain our <code>ViewModel</code>.</p>
<p>Here&rsquo;s the <code>get()</code> method:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">open</span> <span class="k">operator</span> <span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span> <span class="p">:</span> <span class="nc">ViewModel</span><span class="p">&gt;</span> <span class="nf">get</span><span class="p">(</span><span class="n">modelClass</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;):</span> <span class="n">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">canonicalName</span> <span class="p">=</span> <span class="n">modelClass</span><span class="p">.</span><span class="n">canonicalName</span>
</span></span><span class="line"><span class="cl">        <span class="o">?:</span> <span class="k">throw</span> <span class="n">IllegalArgumentException</span><span class="p">(</span><span class="s2">&#34;Local and anonymous classes can not be ViewModels&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">get</span><span class="p">(</span><span class="s2">&#34;</span><span class="si">$DEFAULT</span><span class="s2">_KEY:</span><span class="si">$canonicalName</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">modelClass</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This methods call another <code>get()</code> method that additionally accepts a key as a parameter. In this case, the key is a concatenated string consisting of two parts separated by a colon:</p>
<ul>
<li>A <code>DEFAULT_KEY</code> value (which is <code>&quot;androidx.lifecycle.ViewModelProvider.DefaultKey&quot;</code>).</li>
<li>A canonical name of our <code>ViewModel</code> class.</li>
</ul>
<p>This key will be used to identify our <code>ViewModel</code> object in the <code>HashMap&lt;String, ViewModel&gt;</code> that we saw earlier in the <code>ViewModelStore</code> class.</p>
<p>Here&rsquo;s the second <code>get()</code> method:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">open</span> <span class="k">operator</span> <span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span> <span class="p">:</span> <span class="nc">ViewModel</span><span class="p">&gt;</span> <span class="nf">get</span><span class="p">(</span><span class="n">key</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="n">modelClass</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;):</span> <span class="n">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">viewModel</span> <span class="p">=</span> <span class="n">store</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">modelClass</span><span class="p">.</span><span class="n">isInstance</span><span class="p">(</span><span class="n">viewModel</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">factory</span> <span class="k">as</span><span class="p">?</span> <span class="n">OnRequeryFactory</span><span class="p">)</span><span class="o">?.</span><span class="n">onRequery</span><span class="p">(</span><span class="n">viewModel</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">viewModel</span> <span class="k">as</span> <span class="n">T</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nd">@Suppress</span><span class="p">(</span><span class="s2">&#34;ControlFlowWithEmptyBody&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">viewModel</span> <span class="o">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// TODO: log a warning.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">viewModel</span> <span class="p">=</span> <span class="k">if</span> <span class="p">(</span><span class="n">factory</span> <span class="k">is</span> <span class="n">KeyedFactory</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">factory</span><span class="p">.</span><span class="n">create</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">modelClass</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">factory</span><span class="p">.</span><span class="n">create</span><span class="p">(</span><span class="n">modelClass</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">store</span><span class="p">.</span><span class="n">put</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">viewModel</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">viewModel</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Without going into too many details, this method basically returns an existing <code>ViewModel</code> specified by the key (if there is one) or creates a new one of the desired type using the provided factory.</p>
<p>Here we can see the <code>ViewModelStore</code> in action. It&rsquo;s used to get an existing <code>ViewModel</code> instance (<code>var viewModel = store[key]</code>) or to store a newly created one (<code>store.put(key, viewModel)</code>).</p>
<p>At this point, we&rsquo;ve finally obtained the <code>ViewModel</code> instance that we wanted. It was either the one we already had access to or a completely new instance.</p>
<p>Ok, we’ve covered a lot of ground. It might be worth pausing for a moment to wrap up what we’ve found so far:</p>
<ul>
<li>Every activity and fragment (from the <code>androidx</code> packages) has a component called <code>ViewModelStore</code>. How do we know it? They declare this fact by implementing the <code>ViewModelStoreOwner</code> interface. The <code>ViewModelStore</code> has references to all <code>ViewModels</code> used by this activity or fragment. This component is preserved across configuration changes. Later in this post, we will see how it&rsquo;s done.</li>
<li>When we call <code>private val viewModel: MyViewModel by viewModels()</code> in our activity (or fragment), we create a lazy property delegate that will initialize our <code>ViewModel</code> when we first access the <code>viewModel</code> variable. Internally, the code will create a correct instance and store it in the activity&rsquo;s (or fragment&rsquo;s) <code>ViewModelStore</code> or return the previous instance instead (if there was one).</li>
</ul>
<h2 id="the-survival">The survival</h2>
<p>We learned that it&rsquo;s the <code>ViewModelStore</code> that stores our <code>ViewModels</code>. The original question:</p>
<blockquote>
<p>How ViewModels survive configuration changes?</p>
</blockquote>
<p>can therefore be rephrased to:</p>
<blockquote>
<p>How <strong>ViewModelStores</strong> survive configuration changes?</p>
</blockquote>
<p>Let&rsquo;s focus on activities. Going back to the <code>getViewModelStore()</code> method from the <code>ComponentActivity</code>, we can notice that it calls another method called <code>ensureViewModelStore()</code> before returning its member instance.</p>
<p>As a refresher, here&rsquo;s the <code>getViewModelStore()</code> method:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="n">ViewModelStore</span><span class="w"> </span><span class="nf">getViewModelStore</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">getApplication</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">throw</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">IllegalStateException</span><span class="p">(</span><span class="s">&#34;Your activity is not yet attached to the &#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="o">+</span><span class="w"> </span><span class="s">&#34;Application instance. You can&#39;t request ViewModel before onCreate call.&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">ensureViewModelStore</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="n">mViewModelStore</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>and this is the <code>ensureViewModelStore()</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kt">void</span><span class="w"> </span><span class="nf">ensureViewModelStore</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">mViewModelStore</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">NonConfigurationInstances</span><span class="w"> </span><span class="n">nc</span><span class="w"> </span><span class="o">=</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="p">(</span><span class="n">NonConfigurationInstances</span><span class="p">)</span><span class="w"> </span><span class="n">getLastNonConfigurationInstance</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">nc</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">// Restore the ViewModelStore from NonConfigurationInstances</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">mViewModelStore</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nc</span><span class="p">.</span><span class="na">viewModelStore</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">mViewModelStore</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">mViewModelStore</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ViewModelStore</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>And there we go! It seems that we&rsquo;ve found what we&rsquo;ve been looking for.</p>
<p>This method first checks if the <code>mViewModelStore</code> member variable is null. If it is, we <strong>restore</strong> the previous <code>ViewModelStore</code> (if there is any, otherwise, it creates a new one) using the <code>getLastNonConfigurationInstance()</code> method. This method returns an instance of the <code>NonConfigurationInstances</code> class that&rsquo;s defined as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="kd">class</span> <span class="nc">NonConfigurationInstances</span><span class="w"> </span><span class="p">{</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">Object</span><span class="w"> </span><span class="n">custom</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">ViewModelStore</span><span class="w"> </span><span class="n">viewModelStore</span><span class="p">;</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>As we can see, it has our <code>ViewModelStore</code> object.</p>
<p>Now we know how our <code>ViewModelStores</code> are restored. There is one final piece of the puzzle to solve. We need to find out how they are saved. Let&rsquo;s start by looking at the documentation of the<code>getLastNonConfigurationInstance()</code> method:</p>
<blockquote>
<p>Retrieve the non-configuration instance data that was previously returned by <code>onRetainNonConfigurationInstance()</code>.</p>
</blockquote>
<p>I think we are getting pretty close. Let&rsquo;s dive into the <code>onRetainNonConfigurationInstance()</code> method. First, this is what the documentation says about it:</p>
<blockquote>
<p>Called by the system, as part of destroying an activity due to a configuration change, when it is known that a new instance will immediately be created for the new configuration. You can return any object you like here, including the activity instance itself, which can later be retrieved by calling <code>getLastNonConfigurationInstance()</code> in the new activity instance.</p>
</blockquote>
<p>And this is what the method looks like in the <code>ComponentActivity</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Object</span><span class="w"> </span><span class="nf">onRetainNonConfigurationInstance</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Skipping the irrelevant parts...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">NonConfigurationInstances</span><span class="w"> </span><span class="n">nci</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">NonConfigurationInstances</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">nci</span><span class="p">.</span><span class="na">custom</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">custom</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">nci</span><span class="p">.</span><span class="na">viewModelStore</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">viewModelStore</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="n">nci</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>As you can see, this method prepares the instance of the <code>NonConfigurationInstances</code> class that will be retained across configuration change. It has our current <code>ViewModelStore</code> which means we will be able to successfuly restore it afterwards in the <code>getLastNonConfigurationInstance()</code>.</p>
<p>And that&rsquo;s it! All that seems so magical about <code>ViewModels</code> at first glance is just a combination of using this pair of methods from the <code>Activity</code> class:</p>
<ul>
<li><code>onRetainNonConfigurationInstance()</code></li>
<li><code>getLastNonConfigurationInstance()</code></li>
</ul>
<p>The process of saving and restoring the <code>ViewModelStore</code> in fragments is very similar. If you are interested, I encourage you to explore the source code to find it out by yourself.</p>
<h2 id="viewmodels-and-process-death">ViewModels and process death</h2>
<p>Here&rsquo;s one thing worth keeping in mind. As mentioned in the introduction, the <code>ViewModel</code> class allows data to survive <strong>configuration changes</strong> such as screen rotations, enabling the multi-window mode, etc.</p>
<p>However, the system may destroy your application process while the user is away interacting with other apps. In such a case, the activity instance is destroyed, along with any state stored in it. This is called a <em>process death</em>. <code>ViewModels</code> <strong>don&rsquo;t survive</strong> a system-initiated process death.</p>
<p>This is why you should use <code>ViewModel</code> objects in combination with <code>onSaveInstanceState()</code> or some other disk persistence. To avoid some boilerplate when using the first approach, you might want to take a look at the <a href="https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate">SavedStateHandle</a>.</p>
<h2 id="summary">Summary</h2>
<p>In order to effectively use <code>ViewModels</code> in our Android apps, it&rsquo;s not necessary to entirely understand the details of their implementation. However, many developers are simply curious about how some things work behind the scenes. Knowledge of the internals can make it easier to spot potential edge cases or pitfalls and simplify debugging in the future.</p>
<p>I hope you learned something new after reading this post and that it satisfied your curiosity. If there are still some parts that you find confusing, feel free to reach me on <a href="https://twitter.com/ClouddJR/">Twitter</a> and ask some questions. I will do my best to answer them.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>My key takeaways from The Pragmatic Programmer</title>
      <link>https://arkadiuszchmura.com/posts/my-key-takeaways-from-the-pragmatic-programmer/</link>
      <pubDate>Sun, 20 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/my-key-takeaways-from-the-pragmatic-programmer/</guid>
      <description>In this blog post, I list things that resonate with me most after reading this book.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this post, I&rsquo;d like to write a quick summary of key ideas presented in the book <em>The Pragmatic Programmer</em> written by David Thomas and Andrew Hunt. It will serve me (and you, hopefully) as a reference I can look up later to remind myself of these timeless concepts.</p>
<p>Obviously, it&rsquo;s not possible to cover everything here. I highly recommend reading this book to get a full picture. Here, I focus on things that are in my opinion most important in regards to our everyday work and advancing our careers as programmers.</p>
<p>This book is not strictly about code. It&rsquo;s not examining a specific language, tool, framework, or pattern. It&rsquo;s about a philosophy of being pragmatic in our craft. It&rsquo;s aimed at people who want to become more effective and productive programmers.</p>
<p>The word <em>pragmatic</em> comes from the Latin <em>pragmaticus</em>, which means “skilled in business”. Let&rsquo;s see what the authors think it means to be a pragmatic programmer.</p>
<h2 id="takeaways">Takeaways</h2>
<p>The ideas listed below are presented in the same order as they appear in the book. The order doesn&rsquo;t imply importance. This means that the last idea is not the least important or useful.</p>
<h3 id="craftsmanship">Craftsmanship</h3>
<p>Programming is a craft and it&rsquo;s a difficult job. No doubt about it. Every day, we try to transform vague user requirements into a language that computers can understand.</p>
<p>The authors compare programmers to craftsmen who employ a set of good-quality tools and can choose the best one for the job at hand. We ought to do the same thing. It&rsquo;s not enough to learn one language and stick with it throughout our entire career. We should aspire to be polyglots that can adapt to the current situation by utilizing the best possible tools to solve the problem.</p>
<blockquote>
<p>If all you have is a hammer, everything looks like a nail.</p>
</blockquote>
<p>In an attempt to become pragmatic, we must also ask questions and be curious. <em>How does this library work?</em> <em>Why did you decide to do it this way?</em> <em>Is it the best way to solve this?</em> This will deepen our understanding, broaden our perspective and lead to a feeling of mastery and continuous improvement.</p>
<h3 id="be-responsible-and-dont-complain">Be responsible and don&rsquo;t complain</h3>
<p>Pragmatic programmers aren&rsquo;t afraid to admit ignorance or error. We are humans. A lot of things can go wrong even if we do our best with testing, documentation, or automation. The question is not <em>if</em> it happens, but <em>when</em>. It&rsquo;s unavoidable.</p>
<p>The best we can do then is to acknowledge the problem, take responsibility for it, and try to offer options to fix it. Unfortunately, what we usually do instead is complain. We blame someone or something else - coworkers, programming languages, tools, etc.</p>
<p>Imagine that it wasn&rsquo;t our code that introduced the error, but someone else&rsquo;s. <strong>It doesn&rsquo;t matter</strong>. We all work towards the same goal. If we help our teammates, they will do the same thing for us later. This builds a healthy relationship in the team. Others will also remember that you can be trusted.</p>
<blockquote>
<p>Suggest options. Don&rsquo;t make excuses.</p>
</blockquote>
<p>Before I approach anyone and tell them why something can&rsquo;t be done or that it&rsquo;s not my fault, I stop and listen to myself. How does this excuse sound? What will they think of me?</p>
<p>I try to position myself in their shoes. How do I react when someone (such as an auto mechanic) comes to me with a lame excuse? What do I think of them or their company after that?</p>
<h3 id="dont-accept-any-broken-window">Don&rsquo;t accept any broken window</h3>
<p>The authors describe a phenomenon of cities where some buildings are in perfectly well shape while others have gone really bad. Researchers discovered that there exists a trigger mechanism that can quickly turn a beautiful and clean building into an abandoned derelict.</p>
<p>What is that trigger? <strong>A broken window</strong>.</p>
<p>Here is what they found:</p>
<blockquote>
<p>One broken window, left unrepaired for any substantial length of time, instills in the inhabitants of the building a sense of abandonment—a sense that the powers don’t care about the building. So another window gets broken. People start littering. Graffiti appears. Serious structural damage begins. [&hellip;]</p>
</blockquote>
<p>In my opinion, this analogy suits software quite well. I&rsquo;m sure we&rsquo;ve all seen codebases that were doing just fine only to find later that they are slowly descending to a ruin.</p>
<p>A broken window could be any shortcut that we&rsquo;ve taken to make things easier for us at the moment. A broken design or architecture, wrong decision, poor or dirty code.</p>
<p>If we allow a single broken window in our codebase, we can be sure that there will be more to come.</p>
<h3 id="your-growth-is-your-responsibility">Your growth is your responsibility</h3>
<p>We all know we should stay on top of technologies and the latest trends and constantly keep learning. I think no one has to be convinced about this anymore.</p>
<p>What I like about this book is that it gives us some very specific guidelines for building our knowledge portfolio that we can take inspiration from:</p>
<ul>
<li><strong>Learn at least one new language every year</strong>. You&rsquo;ll learn several different approaches to solving various problems. It&rsquo;ll broaden your thinking.</li>
<li><strong>Read a technical book each month</strong>. A book will give you the depth that you won&rsquo;t find in podcasts, blog posts, or online videos.</li>
<li><strong>Take classes or workshops</strong>. Look for occasions to expand your knowledge.</li>
<li><strong>Participate in local user groups or meetups</strong>. Don&rsquo;t just go and listen. Participate actively.</li>
<li><strong>Experiment with different environments</strong>. For example, if you&rsquo;ve only worked with IDE, consider spending some time with a text editor, and vice versa.</li>
<li><strong>Stay current</strong>. Follow interesting people in your field, read blogs, make side-projects.</li>
</ul>
<h3 id="easier-to-change">Easier To Change</h3>
<p>Programmers often like to argue and discuss which framework, language, or design pattern is the best.</p>
<p>When we learn to program, we are taught about different rules or principles that we are supposed to follow. <a href="https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it">YAGNI</a> (You Aren&rsquo;t Gonna Need It), <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> (Don&rsquo;t Repeat Yourself), <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS</a> (Keep It Simple, Stupid) the <a href="https://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter</a>, and a whole bunch of others.</p>
<p>Authors argue that at the end of the day, what really matters is that the system we are working on is <strong>Easier To Change (ETC)</strong>.</p>
<p>Why should we favor composition over inheritance? Because it makes things easier to change.</p>
<p>Why is decoupling useful? Because by isolating concerns we make them easier to change.</p>
<p>Why do we always make sure to follow the Single Responsibility rule? Because if there is a change in the requirements, we only have to touch a single module. ETC.</p>
<p>ETC is a value, not a rule, that should help you make decisions. By asking whether the approach I&rsquo;m taking will make it relatively easy to change it later when needed, you will usually know which path to choose.</p>
<h3 id="prototypes-and-tracer-bullets">Prototypes and Tracer Bullets</h3>
<p>One of the ideas behind prototyping is that you will throw away every piece of code you wrote to explore or try the concept.</p>
<p>For example, to prove that your idea is doable, you could start with a more forgiving language like Python. At this point, you don&rsquo;t need any user interface, specific architecture, or design. None of the code will end up in the codebase anyway.</p>
<p>When you verify that your vision is indeed possible to implement, you ditch everything and recode it properly using the lessons you&rsquo;ve learned and tools that work on your target&rsquo;s platform.</p>
<p>On the other spectrum, we have tracer bullets. Authors use the term tracer bullet development to visually illustrate the need for immediate feedback under actual conditions with a moving goal.</p>
<p>It&rsquo;s an important distinction. With the tracer bullets approach, you don&rsquo;t throw away any code when you finish. The code you write will end up in the final product. The only difference is that you focus on the key aspects of the system first.</p>
<p>For instance, imagine building a mobile application where users fill out a form. That submission hits our server to be processed later. A finished app requires a pleasant user interface with animations, validation on both the client and server-side, well-formatted responses, etc.</p>
<p>With the tracer bullet development approach, we would first focus on the most important things. We would start with a very basic form without any validation, and the submission would be printed to the console or saved in logs on the server-side without hitting the database.</p>
<p>At this point, we have a solid foundation. We&rsquo;ve established the communication between the mobile app and our server. The code is covered by tests. Now, we have something to show to our clients or teammates. Later, we can expand and add more functionality with confidence.</p>
<h3 id="estimating-time">Estimating time</h3>
<p>Managers or clients often ask us to evaluate how long something will take. Estimating time is extremely difficult, especially when people expect us to provide a single number, like 12 days.</p>
<p>In the real world, people don&rsquo;t estimate with single numbers. They use a range of scenarios.</p>
<p>There is a methodology that adopts this style of assessment. It&rsquo;s called <em>Program Evaluation Review Technique</em>, or <a href="https://en.wikipedia.org/wiki/Program_evaluation_and_review_technique"><strong>PERT</strong></a>.</p>
<p>Every PERT task has an optimistic, most likely, and pessimistic estimate. The tasks are arranged into a dependency network, and then you use some simple statistics to identify likely best and worst times for the overall project.</p>
<p>With this approach, you don&rsquo;t specify one fixed number. It helps to account for different potential problems that we might encounter along the way.</p>
<p>Of course, a single method won&rsquo;t suddenly make estimating easy. That&rsquo;s why it&rsquo;s important to record our estimates. When we finish a project or an iteration, we can see how close we were. If the gap was significant, we should stop and think about a reason. With time and practice, we will give more accurate estimations.</p>
<h3 id="be-fluent-with-your-tools">Be fluent with your tools</h3>
<p>If you recall yourself trying to learn how to drive a car, you might remember that you had to think about every action you took. Later, with more experience, controlling the car became automatic and instinctive.</p>
<p>We should aim for the same automation mechanisms when using our tools. If we don&rsquo;t have to think about all the keyboard shortcuts and options while programming, our minds will have more capacity to think about the problem at hand.</p>
<p>The authors give us some tips about what it means to be fluent with our tools. You are fluent when you can:</p>
<ul>
<li>When editing text, move and make selections by character, word, line, and paragraph.</li>
<li>When editing code, move by various syntactic units (matching delimiters, functions, modules, etc.).</li>
<li>Reindent code following changes.</li>
<li>Comment and uncomment blocks of code with a single command.</li>
<li>Split the editor window into multiple panels and navigate between them.</li>
<li>Navigate to a particular line number.</li>
<li>Search for both strings and regular expressions.</li>
<li>Temporarily create multiple cursors based on a selection or a pattern match, and edit the text at each in parallel.</li>
<li>Run the current project’s tests.</li>
</ul>
<p>Ideally, you can do all of this without using a mouse or a trackpad.</p>
<h3 id="debug-with-confidence">Debug with confidence</h3>
<p>Debugging and finding errors is not always fun. There is no point in making it more problematic than it has to be. The authors give us some general steps that we can follow to make this process at least a bit more effortless for us.</p>
<p>First, before you start debugging, you should adopt the right mindset. Turn off all defensive mechanisms that protect your ego. Also, don&rsquo;t waste time thinking that this couldn&rsquo;t happen or it was impossible. You are looking at the stack trace right now. It clearly did happen.</p>
<p>Then, always begin with making a bug reproducible. If you can&rsquo;t do it, you will never know if it&rsquo;s fixed. Ideally, try to make it possible to reproduce the error with a single command or action.</p>
<p>The root of the problem may lie in the OS, the compiler, or a third-party library. But that should never be your first thought. Always assume that the bug exists in your code and start from there. Because even if it does lie in the library, you would still have to trace the problem in your code before submitting the bug report to the maintainers.</p>
<p>Lastly, make sure that whatever was the problem, you’ll know if it occurs again. If your tests pass with the bug in the code, you can&rsquo;t trust them with catching the bug next time.</p>
<p>Write a test, see it fail, fix the bug, and sleep well knowing that you are covered.</p>
<h3 id="engineering-daybook">Engineering daybook</h3>
<p>Have you ever found yourself trying to remember how you solved a particular problem? You probably wished at that moment that you had written the solution and explanation somewhere. It would save you a lot of time and energy.</p>
<p>That&rsquo;s why Andy and Dave recommend keeping an engineering daybook when working. It&rsquo;s a kind of journal in which you record what you do, things you learned, sketches of ideas, notes from meetings, variable values when debugging, etc.</p>
<p>The daybook has many benefits:</p>
<ul>
<li>It&rsquo;s more reliable than memory.</li>
<li>It acts as a kind of rubber duck. It forces you to think about a problem before writing it down.</li>
<li>It serves as a database of documented memories. You can look at it and think about the people you collaborated with, projects you worked on, and problems you faced.</li>
</ul>
<p>The authors suggest sticking to a plain old pen and paper. However, I think it might make sense to use a digital version for one reason. It&rsquo;s searchable, and you can categorize your notes more easily.</p>
<h3 id="dead-programs-dont-lie">Dead programs don&rsquo;t lie</h3>
<p>Programmers tend to take a defensive approach when programming. We try to catch or rescue all possible exceptions, check for nullability before using variables, verify that the lists passed as arguments are not empty, etc. We avoid crashes at all costs.</p>
<p>The problem with this approach is that the app or system we are working on might stop working <strong>silently</strong> on production without us having any way of detecting it.</p>
<p>Sure, we checked that the list we wanted to display on the screen wasn&rsquo;t empty or null. There will be no exception thrown when we try to access it. But what will the user see? Most likely a blank screen. Our app will be in a state that it wasn&rsquo;t designed for. At this point, it&rsquo;s hard to tell why the list was empty. Did we forget to populate it? Did we receive corrupted data from the backend?</p>
<p>If our app gets in a weird state, it would be nice to know it. That&rsquo;s why unhandled exceptions are not always such a bad thing. They are collected by your crash reporting tool and will help you find the root of the problem.</p>
<p>Additionally, allowing our program to continue after entering an inappropriate state might be disastrous. Anything it does from this point forward can introduce strange problems like inconsistent or corrupted data sent to our production database.</p>
<blockquote>
<p>A dead program does a lot less damage than a crippled one.</p>
</blockquote>
<p>I also recommend reading <a href="https://jeroenmols.com/blog/2017/03/08/appcrash/">this</a> article (and its comment section for contrasting opinions) about crashes in mobile apps.</p>
<h3 id="take-small-steps">Take small steps</h3>
<p>It&rsquo;s usually better to take small and deliberate steps. You then check for feedback and adjust before proceeding. Feedback can take many forms, for example, an MVP that you show to your client or unit tests that verify the correctness of your last code change.</p>
<p>We should avoid steps that are too big. They require an attempt to predict the future. No one can do that. You might want to think twice when you find yourself doing one of those things:</p>
<ul>
<li>Estimate completion dates months in advance.</li>
<li>Guess users&rsquo; future needs and preferences.</li>
<li>Predict future tech trends and tools.</li>
</ul>
<p>Around two decades ago, debates raged in online forums over questions like &ldquo;Who would win the desktop GUI wars, Motif or OpenLook?&rdquo;. Chances are, you&rsquo;ve never heard of these technologies. Remember this story next time you see yourself fortune-telling.</p>
<h3 id="decoupling">Decoupling</h3>
<p>We want our code to be as flexible as possible. Coupled code is hard to change. Modifications in one place can have secondary effects in other locations.</p>
<p>The authors present this snippet of code to demonstrate the problem:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">applyDiscount</span><span class="p">(</span><span class="n">customer</span><span class="p">:</span> <span class="n">Customer</span><span class="p">,</span> <span class="n">orderId</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="n">discount</span><span class="p">:</span> <span class="n">Discount</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">customer</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">orders</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">orderId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">getTotals</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">applyDiscount</span><span class="p">(</span><span class="n">discount</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>What we can see here is the so-called <em>Train Wreck</em>. This code is traversing five levels of abstraction, from customer to total amounts. Our top-level code has to know about each level&rsquo;s internal implementation. It knows that the <code>customer</code> object exposes orders, that the <code>orders</code> have a find method, and that the order object has a <code>totals</code> object which contains information about discounts and grand totals.</p>
<p>There is a lot of coupling here. Imagine that someone decides that no order can have a discount of more than 50%. Where should we implement this change? You might think that it belongs to <code>applyDiscount()</code>. It&rsquo;s true, but the problem is that there might be other places that modify the <code>totals</code> object besides this function. We would have to find all of them and adjust accordingly. That&rsquo;s potentially a lot of work.</p>
<p>So, what&rsquo;s the solution? Andy and Dave have a principle that they call:</p>
<blockquote>
<p>Tell, Don&rsquo;t Ask.</p>
</blockquote>
<p>We shouldn&rsquo;t ask about an object&rsquo;s internal state and then modify it based on the information we receive. We should tell it to do what we need.</p>
<p>We could refactor the code above to something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">private</span> <span class="k">fun</span> <span class="nf">applyDiscount</span><span class="p">(</span><span class="n">customer</span><span class="p">:</span> <span class="n">Customer</span><span class="p">,</span> <span class="n">orderId</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="n">discount</span><span class="p">:</span> <span class="n">Discount</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">customer</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">findOrder</span><span class="p">(</span><span class="n">orderId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">applyDiscount</span><span class="p">(</span><span class="n">discount</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>With this change, our top-level code doesn&rsquo;t have to know that the order class uses a separate object to store its totals and discounts. We also don&rsquo;t fetch a list of orders from the customer and search for a specific one. We get the order that we want directly from the customer.</p>
<p>Right now, we have only one place that manages discounts and all rules can be encapsulated there.</p>
<h3 id="fear-of-the-blank-page">Fear of the blank page</h3>
<p>I&rsquo;m sure we&rsquo;ve all experienced this. We start working on a new feature or a completely new project. The cursor is blinking. The screen is empty and ready to be filled with code. For some reason, the experience is very intimidating. We put off making the initial commitment of starting.</p>
<p>The authors say the most likely reason we feel this way is that we are afraid of making a mistake. We fear the architecture we are implementing will not be flexible enough. We worry that the code will not be readable by other developers. We stress about introducing new bugs or problems. Potentially, we may think that the task is beyond our skills. We can&rsquo;t see our way through to the end.</p>
<p>Andy and Dave claim that they found a brain hack that seems to work in this kind of situation:</p>
<blockquote>
<p>Pretend that you are prototyping.</p>
</blockquote>
<p>Remember that prototypes get thrown away, even if they don&rsquo;t fail. If your mind knows this, you are less likely to feel anxious. If anything goes wrong, you will stash all of it away. No problem. But what&rsquo;s usually happening is this. After some time, you find that the code flies from your brain into the editor. The initial stress is gone. You start to see the bigger picture. You know how to proceed.</p>
<p>To make it even more clear to you, the authors suggest writing &ldquo;I&rsquo;m prototyping&rdquo; on a sticky note and attaching it on the side of your screen.</p>
<p>I tried this trick a couple of times and it worked for me. It helps with one of the hardest things - forcing yourself to start writing.</p>
<h3 id="dont-program-by-coincidence">Don&rsquo;t program by coincidence</h3>
<p>When you use a technology you don&rsquo;t understand, you program by coincidence. If you&rsquo;re unsure why something works, you won&rsquo;t know why it fails. Programming by coincidence is the opposite of programming deliberately.</p>
<p>&ldquo;It doesn&rsquo;t work without it&rdquo; is not a good reason to keep maintaining a specific portion of code. Unnecessary calls slow the program down or introduce bugs that are difficult to spot. What&rsquo;s worse is that other developers won&rsquo;t usually bother trying to mess with it to improve it. &ldquo;If it works now, it&rsquo;s better to leave it alone&hellip;&rdquo;</p>
<p>We all want to work with error-free code and catch all bugs as early in the development cycle as possible. To do that, we should always program deliberately. Make sure you have at least a basic understanding of all the libraries and tools you use in your application or system. Asks yourself questions - would I be able to explain this piece of code to a more junior programmer? If not, perhaps you are relying on coincidence.</p>
<p>Next time something seems to work, but you don’t know why, make sure it isn’t just a coincidence. Don&rsquo;t assume anything. Prove it.</p>
<h3 id="code-is-a-garden">Code is a garden</h3>
<blockquote>
<p>A tourist visiting England’s Eton College asked the gardener how he got the lawns so perfect. “That’s easy,” he replied, “You just brush off the dew every morning, mow them every other day, and roll them once a week.”</p>
<p>“Is that all?” asked the tourist. “Absolutely,” replied the gardener. “Do that for 500 years and you’ll have a nice lawn, too.”</p>
</blockquote>
<p>Code is not static. It constantly evolves. Inaccurately, some people associate software development with building construction. It implies that there is an architect that draws the initial blueprints. Then, contractors dig the foundation, build the superstructure and apply final touches. At this point, there is no easy way to change anything. The project is considered finished and the tenants move in.</p>
<p>The software doesn&rsquo;t quite work that way. It&rsquo;s more like a garden when things change all the time. You plant different things according to the initial plan and environment. After observing the typical weather conditions, you may move plantings to other places. Overgrown plants get split. You pull weeds and fertilize plantings. The health of the garden needs constant monitoring and adjustments.</p>
<p>The gardening metaphor is much closer to the realities of software development. Laws of physics don&rsquo;t constrain code as they do with buildings.</p>
<p>This philosophy led to a discipline called <em>Refactoring</em>. Martin Fowler defines it as a &ldquo;disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.&rdquo; This technique inlines with the idea that code requires constant improvement and refinement.</p>
<h3 id="tests-arent-only-about-finding-errors">Tests aren&rsquo;t only about finding errors</h3>
<p>When we ask developers why they write tests, most of them would say &ldquo;to make sure the code works&rdquo;. It&rsquo;s a perfectly valid reason. But Andy and Dave argue that there is much more to tests than that.</p>
<p>They believe that the sole act of <strong>thinking</strong> about tests while coding is the main benefit of tests.</p>
<p>Consider the following example. You are working on a class that is supposed to fetch tomorrow&rsquo;s lottery numbers. That&rsquo;s the code you have written so far:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">FetchTomorrowsLotteryNumbersUseCase</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">service</span> <span class="p">=</span> <span class="n">LotteryNumbersService</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">operator</span> <span class="k">fun</span> <span class="nf">invoke</span><span class="p">()</span> <span class="p">=</span> <span class="n">service</span><span class="p">.</span><span class="n">fetch</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The above code works completely fine when you run it. Now what&rsquo;s left is to wait for tomorrow and hope that this service is reliable.</p>
<p>But because you are constantly thinking about tests, you start wondering how to write tests for the given code. It would be reasonable to use some test data and not rely on the remote service. The current implementation makes it problematic because we don&rsquo;t control how this class interacts with data. The easiest way to make it possible during tests is to pass the service as a parameter. The code could now look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">FetchTomorrowsLotteryNumbersUseCase</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">service</span><span class="p">:</span> <span class="n">LotteryNumbersService</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">{</span>     
</span></span><span class="line"><span class="cl">    <span class="k">operator</span> <span class="k">fun</span> <span class="nf">invoke</span><span class="p">()</span> <span class="p">=</span> <span class="n">service</span><span class="p">.</span><span class="n">fetch</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Thinking about testing made us reduce coupling in the code (by passing in a service that we can control from the outside) and increase flexibility. When we think about writing tests for the code we are working on, we imagine ourselves as clients of the code, not its authors.</p>
<h3 id="be-proud-of-your-work">Be proud of your work</h3>
<p>The authors say that pragmatic programmers should be proud to sign their work just like artisans of an earlier age. When we are accountable for a piece of code, we aspire to do a job we can be proud of.</p>
<p>The opposite of it is anonymity. It provides room for mistakes, sloppiness, and bad code, especially on large projects. It creates an environment where no one feels any responsibility.</p>
<p>We should aim to associate our signatures with an indication of high quality. When other developers see our code, they should expect it to be solid, well-written, thoroughly tested, and documented.</p>
<h2 id="summary">Summary</h2>
<p>Andy and Dave end the book by concluding that we have a lot of power (and responsibility) as programmers. Systems and devices that we build can shape the lives of millions. How often do we stop and think about this?</p>
<p>We should do our best to protect the users from any potential harm. If we are involved in a project that requires us to do something against our beliefs or values, we shouldn&rsquo;t be afraid to say &ldquo;no&rdquo;. Would I enjoy using this software as a user? Would I be comfortable with my sensitive data being shared with this company? Do I know something important that users don&rsquo;t?</p>
<p>We are building the future for ourselves and our descendants. Let&rsquo;s envision the future everyone would like to live in and have the courage to work on it every day.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Do not change the package name or class name of your AppWidgetProvider</title>
      <link>https://arkadiuszchmura.com/posts/do-not-change-the-package-name-or-class-name-of-your-app-widget-provider/</link>
      <pubDate>Tue, 22 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/do-not-change-the-package-name-or-class-name-of-your-app-widget-provider/</guid>
      <description>If you do this, widgets that were placed on the home screen by your users will simply disappear.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>When creating a widget for your Android app, one of the components that you need to define is a class that extends <a href="https://developer.android.com/reference/android/appwidget/AppWidgetProvider">AppWidgetProvider</a>. Through it, you will receive broadcasts when the widget is updated, enabled, disabled, deleted, resized, etc. You can then act accordingly and, for example, refresh the widget&rsquo;s view to display the newest data.</p>
<p>I implemented a widget in <a href="https://play.google.com/store/apps/details?id=com.arkadiusz.dayscounter">one of my apps</a> following the steps mentioned <a href="https://developer.android.com/guide/topics/appwidgets">in the documentation</a> and everything was working just fine.</p>
<p>At least until one day. After noticing that my app is getting bigger, I decided to change the structure of my app a little to package classes by features rather than by layers.</p>
<p>When I changed the package name of my class extending AppWidgetProvider from</p>
<pre tabindex="0"><code>com.arkadiusz.Provider.MyAppWidgetProvider
</code></pre><p>to</p>
<pre tabindex="0"><code>com.arkadiusz.data.providers.MyAppWidgetProvider
</code></pre><p>and relaunched the app, all app&rsquo;s widgets disappeared from my home screen.</p>
<p>I can consider myself lucky for noticing this before releasing the next version of the app and causing this problem for all users.</p>
<p>It is quite strange that changing a package name of one class can produce such a radical effect so let&rsquo;s dive into the Android source code and find out why this is happening.</p>
<h2 id="behind-the-scenes">Behind the scenes</h2>
<p>In Android, a system service responsible for managing widgets across the entire OS is called <a href="https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java">AppWidgetService</a>. This is a component that knows, among other things, <strong>how</strong> and <strong>when</strong> to update your widgets (based, for example, on the information that you specify in your AppWidgetProviderInfo XML).</p>
<p>Internally, some of the variables that it holds are as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Java" data-lang="Java"><span class="line"><span class="cl"><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">Widget</span><span class="o">&gt;</span><span class="w"> </span><span class="n">mWidgets</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">Host</span><span class="o">&gt;</span><span class="w"> </span><span class="n">mHosts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">Provider</span><span class="o">&gt;</span><span class="w"> </span><span class="n">mProviders</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span><span class="w">
</span></span></span></code></pre></div><ul>
<li><strong>mWidgets</strong> stores references to all widgets that are placed within all hosts.</li>
<li><strong>mHosts</strong> stores references to all <a href="https://developer.android.com/reference/android/appwidget/AppWidgetHost">AppWidgetHosts</a>, which are components designed to be used by applications that want to embed widgets in their UI (mostly home screen applications). They provide interaction with the AppWidget service.</li>
<li><strong>mProviders</strong> stores references to all AppWidgetProviders that were registered by currently installed apps. Each Provider object is identified by a <a href="https://developer.android.com/reference/android/content/ComponentName">ComponentName</a> (which stores two pieces of information - package name and the class name). It also keeps references to all widgets that it is responsible for.</li>
</ul>
<p>The AppWidget service also listens for different broadcasts related to application packages (like <code>Intent.ACTION_PACKAGE_ADDED</code> or <code>Intent.ACTION_PACKAGE_REMOVED</code>). It does that to keep its ArrayLists up to date. For example, when a user deletes an app from their device, the service can remove every widget and provider associated with this app because they are no longer needed.</p>
<p>I mentioned earlier that the service identifies each provider by its ComponentName. Well, if we decide to change the provider&rsquo;s package name or class name, the new ComponentName is going to be <strong>different</strong>. This is the root of the problem.</p>
<p>Here is what happens when you modify your provider&rsquo;s package name or class name and then update your app:</p>
<ol>
<li>The AppWidget service is notified about an application package update via a broadcast.</li>
<li>It reads the app&rsquo;s manifest file and finds a new provider that it hasn&rsquo;t seen before (it has a unique ComponentName).</li>
<li>It registers and stores it inside the <strong>mProviders</strong> variable.</li>
<li>Then, the service notices that it keeps a reference to a provider that is no longer used (your previous provider). There is no manifest file that declares it so the service decides that it is safe to <strong>remove</strong> it entirely. As part of the provider&rsquo;s removal process, every widget associated with that provider is removed as well.</li>
<li>You end up with empty widgets on the home screen that are no longer referenced by any component and cannot be updated.</li>
<li>The only way to get them to work again is to add them to the launcher anew.</li>
</ol>
<h3 id="i-am-not-alone">I am not alone</h3>
<p>Interestingly, developers working on the Firefox app faced the same problem. If you look at the <a href="https://github.com/mozilla-mobile/fenix/blob/main/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt#L35">source code</a> of their class extending AppWidgetProvider, you will find a comment at the top warning against modifying the package name or the class name:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">SearchWidgetProvider</span> <span class="p">:</span> <span class="n">AppWidgetProvider</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Implementation note:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// This class name (SearchWidgetProvider) and package name (org.mozilla.gecko.search) should
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// not be changed because otherwise this widget will disappear from the home screen of the user.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// The existing name replicates the name and package we used in Fennec.
</span></span></span></code></pre></div><h2 id="solution">Solution?</h2>
<p>Unfortunately, there is currently no way to solve this problem as the code responsible for this behavior lies beyond our control. The only thing you can do is to make sure not to modify anything related to your widget provider after releasing your app if you don&rsquo;t want your users to lose their existing widgets.</p>
<p>Honestly, in most cases, it won&rsquo;t be a huge deal. Even though users would have to place those widgets again on their home screen, everything will continue to work as previously. However, if the configuration of widgets in your app is complicated and time-consuming, this can cause a lot of frustration.</p>
<h2 id="summary">Summary</h2>
<p>Once you implement widgets in your app and release it, do not change the package name or class name of your class extending AppWidgetProvider. It will wipe out all of your user&rsquo;s existing widgets and possibly bring a flood of 1-star reviews for your app.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to reliably update widgets on Android</title>
      <link>https://arkadiuszchmura.com/posts/how-to-reliably-update-widgets-on-android/</link>
      <pubDate>Sat, 12 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/how-to-reliably-update-widgets-on-android/</guid>
      <description>The default solution with android:updatePeriodMillis doesn&amp;rsquo;t always work.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Users of <a href="https://play.google.com/store/apps/details?id=com.arkadiusz.dayscounter">one of my apps</a> heavily rely on widgets. They place them on their home screens to count days to specific events. It is therefore important to keep those widgets up to date and refresh them at least once per day.</p>
<p>Not long ago, I have been getting some emails (as well as 1-star reviews) from my users reporting that their widgets are not being updated properly on their phones.</p>
<p>The Android documentation says that to update a widget periodically at some interval, you can specify <code>android:updatePeriodMillis</code> attribute on the widget&rsquo;s metadata - AppWidgetProviderInfo XML.</p>
<p>Unfortunately, despite setting this attribute in my app, widgets were still not updated reliably on some users&rsquo; phones.</p>
<p>The problem might be that some vendors <a href="https://dontkillmyapp.com/problem">introduce their own set of rules</a> that restrict background processing and ignore this attribute altogether under some circumstances to artificially save some battery life.</p>
<h2 id="solution">Solution</h2>
<p>Since I could not count on this attribute alone, I needed another solution to support it. Luckily, Android Jetpack has a component that could help me periodically update widgets - WorkManager. As of writing this article, it is the primary recommended API for background processing.</p>
<p>Quoting the documentation, WorkManager handles three types of persistent work:</p>
<ul>
<li><strong>Immediate</strong>: Tasks that must begin immediately and complete soon. May be expedited.</li>
<li><strong>Long Running</strong>: Tasks which might run for longer, potentially longer than 10 minutes.</li>
<li><strong>Deferrable</strong>: Scheduled tasks that start at a later time and can run periodically.</li>
</ul>
<p>Support for the third type of work perfectly matched my use case so I decided to give it a try.</p>
<p>Here are the steps I took to import and setup WorkManager in my app:</p>
<p><strong>1. Import the library into your Android project (<a href="https://developer.android.com/jetpack/androidx/releases/work">using the newest version</a>):</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gradle" data-lang="gradle"><span class="line"><span class="cl"><span class="n">dependencies</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">val</span> <span class="n">work_version</span> <span class="o">=</span> <span class="s2">&#34;2.7.1&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Java only
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">implementation</span><span class="o">(</span><span class="s2">&#34;androidx.work:work-runtime:$work_version&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Kotlin + coroutines
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">implementation</span><span class="o">(</span><span class="s2">&#34;androidx.work:work-runtime-ktx:$work_version&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></div><p><strong>2. Define the work</strong></p>
<p>Here we specify what our work actually <strong>does</strong>. We do this by creating our own implementation of the <code>Worker</code> class and overriding the <code>doWork()</code> method. This method runs asynchronously on a background thread provided by WorkManager.</p>
<p>In this case, we simply grab a list of relevant widget ids and notify the AppWidgetManager to perform an update on them by sending an Intent.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">WidgetUpdateWorker</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">appContext</span><span class="p">:</span> <span class="n">Context</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">workerParams</span><span class="p">:</span> <span class="n">WorkerParameters</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">:</span> <span class="n">Worker</span><span class="p">(</span><span class="n">appContext</span><span class="p">,</span> <span class="n">workerParams</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">doWork</span><span class="p">():</span> <span class="n">Result</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// This line might be different in your case
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">val</span> <span class="py">widgetIds</span> <span class="p">=</span> <span class="nc">DatabaseRepository</span><span class="p">.</span><span class="n">getWidgetIds</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">intent</span> <span class="p">=</span> <span class="n">Intent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nc">AppWidgetManager</span><span class="p">.</span><span class="n">ACTION_APPWIDGET_UPDATE</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="n">appContext</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">MyAppWidgetProvider</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">intent</span><span class="p">.</span><span class="n">putExtra</span><span class="p">(</span><span class="nc">AppWidgetManager</span><span class="p">.</span><span class="n">EXTRA_APPWIDGET_IDS</span><span class="p">,</span> <span class="n">widgetIds</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">appContext</span><span class="p">.</span><span class="n">sendBroadcast</span><span class="p">(</span><span class="n">intent</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nc">Result</span><span class="p">.</span><span class="n">success</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>One thing to note here - <code>MyAppWidgetProvider</code> is a subclass of the <code>AppWidgetProvider</code> that is needed when creating a widget.</p>
<p><strong>3. Define WorkRequest and schedule it</strong></p>
<p>Now that we defined our work, it is necessary to specify <strong>how</strong> and <strong>when</strong> that work should be run. We do this by defining a <code>WorkRequest</code>. In our case, we simply want to run the work periodically at some interval.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">widgetUpdateRequest</span> <span class="p">=</span> <span class="n">PeriodicWorkRequestBuilder</span><span class="p">&lt;</span><span class="n">WidgetUpdateWorker</span><span class="p">&gt;(</span>
</span></span><span class="line"><span class="cl">    <span class="m">4</span><span class="p">,</span> <span class="nc">TimeUnit</span><span class="p">.</span><span class="n">HOURS</span>
</span></span><span class="line"><span class="cl"><span class="p">).</span><span class="n">build</span><span class="p">()</span>
</span></span></code></pre></div><p>Finally, we can put everything together and schedule our work. The code below could be placed in the <code>Application.onCreate()</code> or in your main activity&rsquo;s <code>onCreate()</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="nc">WorkManager</span><span class="p">.</span><span class="n">getInstance</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="n">enqueueUniquePeriodicWork</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;widgetUpdateWork&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nc">ExistingPeriodicWorkPolicy</span><span class="p">.</span><span class="n">KEEP</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">widgetUpdateRequest</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div><p>The first parameter - <code>&quot;widgetUpdateWork&quot;</code> is a unique name that identifies the work.</p>
<p>The <code>ExistingPeriodicWorkPolicy.KEEP</code> flag tells the WorkManager to keep using the existing work if there is one already scheduled with the same name.</p>
<p>The third parameter is a <code>WorkRequest</code> that we&rsquo;ve just defined.</p>
<p>And that&rsquo;s it! The work is now scheduled and our widgets are going to be periodically updated.</p>
<p>As a side note, there are many benefits to using the WorkManager versus relying on the standard way of updating the widgets. Here are some of them:</p>
<ul>
<li>Once you specify the <code>android:updatePeriodMillis</code> attribute, it is fixed and cannot be changed in any other way than updating the app with a new value. On the other hand, you can let your users decide how often widgets should be updated with WorkManager and change this value at runtime.</li>
<li>WorkManager automatically ensures that the scheduled tasks are going to finish even when the OS decides to kill the app to reclaim some memory.</li>
<li>Internally, WorkManager uses JobScheduler (on API 23+) or a combination of AlarmManager and BroadcastReceiver on older versions. This makes it less likely to be restricted by some vendors.</li>
</ul>
<p>After introducing WorkManager, the number of emails from my users about their widgets not being updated properly dropped significantly.</p>
<h2 id="summary">Summary</h2>
<p>To summarize, here are the key points from this post:</p>
<ul>
<li>Some vendors restrict background processing in order to save some battery life. Because of this, the standard way of updating widgets (with the <code>android:updatePeriodMillis</code> attribute) doesn&rsquo;t always work.</li>
<li>To solve this problem, we can introduce WorkManager that will periodically update widgets and make sure that they are up to date.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Beware of the order of operands in some Kotlin Collection operations</title>
      <link>https://arkadiuszchmura.com/posts/beware-of-the-order-of-operands-in-some-kotlin-collection-operations/</link>
      <pubDate>Tue, 01 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://arkadiuszchmura.com/posts/beware-of-the-order-of-operands-in-some-kotlin-collection-operations/</guid>
      <description>The order of operands can drastically affect the performance of your code.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In December 2021 I was working on a problem from the <a href="https://adventofcode.com/">Advent of Code 2021</a> that required getting all elements from two collections that were contained in both of them. In Kotlin, there is an extension function for that use case on <code>Iterable</code> called <code>intersect</code>.</p>
<p>In my case, the first collection was a regular <code>List</code> and the second one was a <code>Set</code>.</p>
<p>The code that I eventually used was analogical to this one:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">x</span> <span class="p">=</span> <span class="p">(</span><span class="m">1.</span><span class="p">.</span><span class="m">1</span><span class="n">_000_000</span><span class="p">).</span><span class="n">toList</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="py">y</span> <span class="p">=</span> <span class="p">(</span><span class="m">1.</span><span class="p">.</span><span class="m">100</span><span class="n">_000</span><span class="p">).</span><span class="n">toSet</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="n">intersect</span> <span class="n">y</span>
</span></span></code></pre></div><p>However, when refactoring the code, I incidentally changed the order of the operands and the last line became <code>y intersect x</code>.</p>
<p>Given the fact it was the only modification to the code I made, I was genuinely surprised to find that my program now runs <strong>a couple of times slower</strong>.</p>
<p>That led me to run some experiments to verify whether this seemingly irrelevant change really affects the performance such drastically or the reason was to be found somewhere else.</p>
<h2 id="the-experiment">The experiment</h2>
<p>I decided to use the same code introduced above and measure the execution time separately for both variants:</p>
<ul>
<li>For <code>x intersect y</code>.</li>
<li>For <code>y intersect x</code>.</li>
</ul>
<p>For each variant, the experiment was repeated 20 times on my machine (MacBook Pro 13-inch, early 2015) and the average time was obtained.</p>
<p>Full code for the experiment:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="line"><span class="cl"><span class="k">val</span> <span class="py">results</span> <span class="p">=</span> <span class="n">mutableListOf</span><span class="p">&lt;</span><span class="n">Long</span><span class="p">&gt;()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">repeat</span><span class="p">(</span><span class="m">20</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">measureTime</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">x</span> <span class="p">=</span> <span class="p">(</span><span class="m">1.</span><span class="p">.</span><span class="m">1</span><span class="n">_000_000</span><span class="p">).</span><span class="n">toList</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">y</span> <span class="p">=</span> <span class="p">(</span><span class="m">1.</span><span class="p">.</span><span class="m">100</span><span class="n">_000</span><span class="p">).</span><span class="n">toSet</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="n">intersect</span> <span class="n">y</span> <span class="c1">// or y intersect x
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}.</span><span class="n">inWholeMilliseconds</span><span class="p">.</span><span class="n">also</span> <span class="p">{</span> <span class="n">results</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="k">it</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">average</span><span class="p">())</span>
</span></span></code></pre></div><p>Here are the results:</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">Variant</th>
          <th style="text-align: left">Time</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left"><code>x intersect y</code></td>
          <td style="text-align: left">224 ms</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>y intersect x</code></td>
          <td style="text-align: left"><strong>4793 ms</strong></td>
      </tr>
  </tbody>
</table>
<p>As you can see, the outcome is quite surprising. What&rsquo;s more, the bigger the <code>y</code> collection, the greater the time difference between those two variants.</p>
<h2 id="findings">Findings</h2>
<p>Overall, as I dig deeper into the topic (including the <a href="https://github.com/JetBrains/kotlin/blob/1.6.0/libraries/stdlib/common/src/generated/_Collections.kt#L1670">source code</a> of the <code>intersect</code> function), I realized that the problem is <strong>not</strong> the order of the operands itself, but rather the fact that the second operand in the slower variant was not of type <code>Set</code>.</p>
<p>Moreover, this problem only exists starting with Kotlin 1.6. In prior versions, both of those tested variants (<code>x intersect y</code> and <code>y intersect x</code>) would yield the same results. That&rsquo;s why it might be worth providing a little story behind this issue:</p>
<h3 id="before-kotlin-16">Before Kotlin 1.6</h3>
<p>In many cases, when running some of the Collection operations (such as aforementioned <code>intersect</code>, <code>minus</code>, <code>removeAll</code> or <code>retainAll</code>), Kotlin tried to optimize them by converting their second operands to a <code>Set</code> under the hood.</p>
<p>Why would it do that?</p>
<p>Let&rsquo;s consider the <code>minus</code> operation. It returns a list consisting of elements from the first collection that are not present in the second collection. It does that by filtering the first collection to keep only the items that are not in the second collection. But how does it know that a specific item is not present in that collection? By calling its <code>contains</code> method.</p>
<p>Typically, the complexity of checking for the existence of an item in a regular list or array is linear. We have to go through each item one by one. On the other hand, that complexity is reduced to a constant time for sets. To check whether an item is present in the set, it is enough to compute its hash code.</p>
<p>For that specific reason, Kotlin tried to introduce this optimization any time it could to improve the performance. But it was not possible in all cases.</p>
<p>The problem was that a collection could override its <code>contains</code> method causing some unexpected behavior down the road.</p>
<p>For instance, imagine we pass a collection with overridden <code>contains</code> method that we count on (for example, an <code>IdentitySet</code>). Kotlin then converts it under the hood to a different type - a <code>HashSet</code>. With this change, we can no longer rely on our custom <code>contains</code> implementation because the initial collection is now of another type. This could lead to some errors that are difficult to debug.</p>
<p>That is why the optimization was applied only in specific cases:</p>
<ul>
<li>When the operand was not implementing a <code>Collection</code> interface (meaning it could not override its <code>contains</code> method).</li>
<li>When the operand is a known implementation of Collection that doesn&rsquo;t override <code>contains</code> (currently only <code>kotlin.collections.ArrayList</code>)</li>
</ul>
<p>However, as it turned out, this optimization was quite problematic for a few reasons:</p>
<ul>
<li>The code responsible for deciding whether to convert the second operand to a <code>Set</code> was quite difficult to read. Therefore, it was not obvious at the first glance if it was going to be converted or not.</li>
<li>Sometimes, we might not be aware of the actual implementation of a specific collection  - it could be &ldquo;hidden&rdquo; behind some interface. So, we cannot easily deduce whether it would get converted or not.</li>
<li>There were some problems (described <a href="https://youtrack.jetbrains.com/issue/KT-24536">here</a>) leading to incorrect results when any element changed its <code>hashCode</code> value after being placed to the converted set.</li>
</ul>
<h3 id="since-kotlin-16">Since Kotlin 1.6</h3>
<p>For the reasons mentioned above, the Kotlin team decided to remove this optimization entirely. Now, the second operand will <strong>never</strong> be converted to a <code>Set</code>. At most, it will be converted to a <code>List</code> if the operand is not implementing the <code>Collection</code> interface.</p>
<p>For a full list of affected API, see <a href="https://youtrack.jetbrains.com/issue/KT-45438">this link</a>.</p>
<p>Because this decision could potentially cause performance degradation in some cases, an inspection was added to inform about this issue offering an option to manually convert the second operand to a <code>Set</code>.</p>
<figure class="align-center ">
    <img loading="lazy" src="/inspection.png#center"
         alt="(The argument can be converted to &lsquo;Set&rsquo; to improve performance)" width="550"/> <figcaption>
            Inspection in IntelliJ IDEA informing about a potential performance issue.<p>(The argument can be converted to &lsquo;Set&rsquo; to improve performance)</p>
        </figcaption>
</figure>

<p>For now, it is possible to enable this optimization back on the JVM with a system property (<code>kotlin.collections.convert_arg_to_set_in_removeAll</code>). This will give more time to the developers that were previously relying on this feature to migrate the affected code.</p>
<p>Although, it is worth mentioning that the possibility of enabling the optimization back is planned to be removed in Kotlin 1.7. The same thing is going to happen to the inspection. It will be <strong>turned off</strong> by default with the next major release. Yet you will be able to turn it on again by going to <code>Preferences</code> -&gt; <code>Editor</code> -&gt; <code>Inspections</code> -&gt; <code>Kotlin</code> -&gt; <code>Other problems</code>.</p>
<p>They give the following explanation for their decision:</p>
<blockquote>
<p>However, we expect this inspection to be quite annoying in places where such time complexity does not that matter, so we plan to disabling it by default in the next version of Kotlin and leaving only an intention.</p>
</blockquote>
<h2 id="summary">Summary</h2>
<p>To summarize, here are the key points from this post:</p>
<ul>
<li>Since Kotlin 1.6, the second operands of some Kotlin Collection operations will no longer be converted to a Set under the hood.</li>
<li>That may have some performance implications, so an inspection was added to inform you about this issue whenever applicable.</li>
<li>However, the inspection will be turned off by default with the next major release of Kotlin (1.7). You might want to consider turning it on again if you think your codebase might benefit from having it.</li>
</ul>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
