<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2025-02-10T06:29:36+00:00</updated><id>/feed.xml</id><title type="html">art and science of coding</title><subtitle></subtitle><author><name>Derek Lee</name></author><entry><title type="html">The Art of Multiplatform Programming: The Secret to Maximizing Shared Code</title><link href="/science/kmm-maximizing-shared-code/" rel="alternate" type="text/html" title="The Art of Multiplatform Programming: The Secret to Maximizing Shared Code" /><published>2022-10-01T00:00:00+00:00</published><updated>2022-10-01T00:00:00+00:00</updated><id>/science/kmm-maximizing-shared-code</id><content type="html" xml:base="/science/kmm-maximizing-shared-code/"><![CDATA[<h1 id="tldr">TL/DR;</h1>
<ul>
  <li>Writing your platform-dependent code for iOS or Android requires first understanding the platform API dependencies to help you craft a shared platform-independent interface.</li>
  <li>Isolate platform dependencies to the smallest surface area possible to increase maintainability and reusability.</li>
  <li>Leveraging Dependency Injection (DI) and the Dependency Inversion Principle (DIP) is key to effective multiplatform programming.</li>
  <li>We can use UML class diagrams as a tool to illustrate the relationship between the platform-dependent code (the low-level components) and the responsibilities of the shared platform-independent interface (the high-level blueprint).</li>
</ul>

<p><br /></p>

<h1 id="the-holy-grail-of-mobile-development">The Holy Grail of Mobile Development</h1>

<p>For as long as mobile development has existed with multiple platforms, the “holy grail” of being able to share code between platforms has been elusive. Additionally, the number of tools already in the graveyard (<a href="https://medium.com/airbnb-engineering/sunsetting-react-native-1868ba28e30a">or on their way there</a>) is steadily increasing, with Kotlin Multiplatform being one of the first to allow sharing code in effectively the same ecosystem while maintaining the ability to access native features as needed. Yet, programmatically one of the biggest challenges is how to accomplish this in a way that is easy to maintain while maximizing the amount of code you can share.</p>

<p>This post will walk you through the steps to identify and isolate platform-dependent code in your app to maximize the amount of code you can share between iOS and Android. Better yet, whether you consider yourself an iOS or Android engineer, you can learn and deploy this technique in your applications today.</p>

<p><strong><em>This post is part of a series on Kotlin Multiplatform:</em></strong></p>
<ol>
  <li><a href="/science/kmm-for-ios-engineers/" target="_blank"><em>The iOS Engineer’s Guide to Beginning Kotlin Multiplatform Development</em></a></li>
  <li><a href="/science/avoid-this-kmm-technique/" target="_blank"><em>Why iOS Engineers Should Avoid This Glorified KMM Technique</em></a></li>
  <li><em>The Art of Multiplatform Programming: The Secret to Maximizing Shared Code</em></li>
</ol>

<p><br /></p>

<h1 id="isolating-platform-dependent-code-step-by-step">Isolating Platform-Dependent Code, Step by Step</h1>

<p>There are only four simple steps to understand, isolate, and implement a platform dependency in your multiplatform application:</p>

<ol>
  <li>Understand the platform-dependent APIs that you need to implement.</li>
  <li>Define the interface needed to satisfy your requirements using only platform-independent types.</li>
  <li>Create a concrete class implementing this interface using Swift inside your iOS app.</li>
  <li>Create a concrete class implementing this interface using Kotlin inside your Android app.</li>
</ol>

<p><br /></p>

<h1 id="haptic-feedback">Haptic Feedback</h1>

<p>Haptic feedback is a fantastic example. It’s simple to understand and practical when dealing with multiple platforms because it requires calling platform-specific APIs.</p>

<h2 id="use-case">Use-Case</h2>

<p>We want to provide haptic feedback (device vibration) to the user when they perform an action in our application.</p>

<h2 id="step-1-understand-platform-dependent-apis">Step #1: Understand Platform-Dependent APIs</h2>

<p>As the <a href="/science/avoid-this-kmm-technique/" target="_blank">last blog post mentioned</a>, crafting a platform-independent API is a challenging part of multiplatform development. Understanding how the implementation looks on all the platforms you’re aiming to support is an essential first step to deciding on what your shared platform-independent interface will be.</p>

<h3 id="ios-platform-dependent-apis">iOS Platform-Dependent APIs</h3>

<p>In iOS, we can use any concrete class that implements the <code class="language-plaintext highlighter-rouge">UIFeedbackGenerator</code> interface to provide haptic feedback to the user. As <a href="https://developer.apple.com/documentation/uikit/uifeedbackgenerator">Apple’s documentation indicates</a>, we simply initialize and prepare the generator and then trigger the feedback when needed.</p>

<p><em>NOTE: Haptic APIs vary depending upon what version of iOS you’re supporting, so please dig into this further if you need to implement this functionality.</em> 📚</p>

<p>An example of triggering haptic feedback on iOS might look like this:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="nv">selectionFeedbackGenerator</span> <span class="o">=</span> <span class="kt">UISelectionFeedbackGenerator</span><span class="p">()</span>
<span class="n">selectionFeedbackGenerator</span><span class="o">.</span><span class="nf">prepare</span><span class="p">()</span>
<span class="n">selectionFeedbackGenerator</span><span class="o">.</span><span class="nf">selectionChanged</span><span class="p">()</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From this code, we can discern that besides having to create an instance of <code class="language-plaintext highlighter-rouge">UISelectionFeedbackGenerator</code>, there are no other platform-specific dependencies to execute this code.</p>

<h3 id="android-platform-dependent-apis">Android Platform-Dependent APIs</h3>

<p>For Android, so far as I understand, one way to access haptic feedback API is from the activity’s <code class="language-plaintext highlighter-rouge">Window</code> object. In addition, there are <a href="https://developer.android.com/reference/android/view/HapticFeedbackConstants">many <code class="language-plaintext highlighter-rouge">HapticFeedbackConstants</code> available</a> for you to choose from.</p>

<p>An example of triggering haptic feedback on Android might look like this:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">window</span>
    <span class="o">?.</span><span class="n">decorView</span>
    <span class="o">?.</span><span class="n">rootView</span>
    <span class="o">?.</span><span class="nf">performHapticFeedback</span><span class="p">(</span><span class="nc">HapticFeedbackConstants</span><span class="p">.</span><span class="nc">CLOCK_TICK</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Is there a better way to do this on Android? Do you have a recommendation based on <a href="https://medium.com/lofelt/the-keys-to-delivering-better-haptics-on-android-f502403c22e7">the varying API levels</a>? <a href="/contact/" target="_blank">Let me know!</a></p>

<h2 id="pro-tip-1-encapsulate-platform-dependent-apis">Pro-Tip #1: Encapsulate Platform-Dependent APIs</h2>

<p>This example raises a common question regarding multiplatform development: how do I handle platform-dependent APIs?</p>

<p>The answer to this is straightforward but requires a shift in mindset to become proficient with:</p>

<blockquote>
  <p>Inject <strong>platform-dependent objects</strong><br />
into <strong>concrete instances</strong><br /> 
conforming to a <strong>platform-independent interface</strong></p>
</blockquote>

<p><em>(No worries if you read that sentence three or four times, and it still doesn’t make sense… it will soon enough!)</em></p>

<p>Discussing how to accomplish this opens the door for us to explore two topics crucial to becoming comfortable with multiplatform development: dependency injection (DI) and the <a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle</a> (DIP).</p>

<h2 id="dependency-injection-in-five-sentences-or-fewer">Dependency Injection in Five Sentences or Fewer</h2>

<p>DI is simply the act of <strong>passing an instance of an object into another object</strong> as opposed to creating dependent objects <em>inside</em> an object.</p>

<p>The following Swift example returns a new <code class="language-plaintext highlighter-rouge">UserModel</code> object and generates the user id as a new random UUID <em>directly inside the function</em> (line #4).</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="kt">UserRepository</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">createUser</span><span class="p">(</span><span class="nv">username</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">UserModel</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">UserModel</span><span class="p">(</span>
            <span class="nv">id</span><span class="p">:</span> <span class="kt">UUID</span><span class="p">()</span><span class="o">.</span><span class="n">uuidString</span><span class="p">,</span>
            <span class="nv">username</span><span class="p">:</span> <span class="n">username</span>
        <span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>With dependency injection, we modify the above code to <em>inject the object</em> responsible for generating the UUID, so neither the <code class="language-plaintext highlighter-rouge">createUser()</code> method nor the <code class="language-plaintext highlighter-rouge">UserRepository</code> is accountable for this logic:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="kt">UserRepository</span> <span class="p">{</span>
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">uuidProvider</span><span class="p">:</span> <span class="kt">UUIDProvider</span>

    <span class="nf">init</span><span class="p">(</span><span class="nv">uuidProvider</span><span class="p">:</span> <span class="kt">UUIDProvider</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">uuidProvider</span> <span class="o">=</span> <span class="n">uuidProvider</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">createUser</span><span class="p">(</span><span class="nv">username</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">UserModel</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">UserModel</span><span class="p">(</span>
            <span class="nv">id</span><span class="p">:</span> <span class="n">uuidProvider</span><span class="o">.</span><span class="n">randomUUID</span><span class="p">,</span>
            <span class="nv">username</span><span class="p">:</span> <span class="n">username</span>
        <span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">UUIDProvider</code> protocol (interface) is defined separately and implements generating a random UUID in the same way as it originally was, only now it is isolated into its own object:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="kd">protocol</span> <span class="kt">UUIDProvider</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">randomUUID</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>

<span class="kd">final</span> <span class="kd">class</span> <span class="kt">RandomUUIDProvider</span><span class="p">:</span> <span class="kt">UUIDProvider</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">randomUUID</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">get</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">UUID</span><span class="p">()</span><span class="o">.</span><span class="n">uuidString</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>At its most basic level, dependency injection <strong>externalizes the creation of any objects used by an object</strong>.</p>

<p>In this case, the <code class="language-plaintext highlighter-rouge">UserRepository</code> calls a method on the <code class="language-plaintext highlighter-rouge">UUID</code> object. We can also say the <code class="language-plaintext highlighter-rouge">UserRepository</code> uses <code class="language-plaintext highlighter-rouge">UUID</code> or the <code class="language-plaintext highlighter-rouge">UserRepository</code> <em>depends upon</em> <code class="language-plaintext highlighter-rouge">UUID</code>.</p>

<p>Identifying what objects a block of code depends upon is crucial to leveraging dependency injection.</p>

<h3 id="when-and-how-to-preform-dependency-injection">When and How to Preform Dependency Injection</h3>

<p>Ideally, we want to inject our dependencies during object creation through the constructor, as this forces the consumer to provide the dependencies at the time of object creation. However, if this isn’t possible, you can 
also inject dependencies directly into functions or by setting properties.</p>

<p>The benefit we reap, in this case, is isolating platform-specific dependencies. Additionally, another advantage is improved testability.</p>

<h2 id="dependency-inversion-principle-dip-in-five-sentences-or-fewer">Dependency Inversion Principle (DIP) in Five Sentences or Fewer</h2>

<p>Yes!! Now we’re getting into the fun stuff! 🎉</p>

<p>Representing the “D” of the <a href="https://en.wikipedia.org/wiki/SOLID">“SOLID” principles</a>, the <a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle (DIP)</a> essentially states that an interface defines responsibilities that an object has, or <strong>the high-level blueprint</strong>, and only the concrete classes that satisfy this interface should contain the <strong>implementation details</strong>. These are details like what kinds of objects, specifically platform-dependent components, are needed to fulfill that behavior.</p>

<h3 id="typical-applications-of-the-dip">Typical Applications of the DIP</h3>

<p>You have likely already seen many DIP examples where object wrappers are used for third-party code to protect oneself from the details of that API leaking into your application. Yet, when engineers don’t take the appropriate precautions to protect themselves and their teams against third-party code, that code can pollute other parts of your codebase and result in a “leaky abstraction.”</p>

<p>This mistake is often easily made when dealing with third-party code because the compiler won’t inform you when you’ve violated this heuristic.</p>

<p>However, it’s nearly impossible to make this mistake when working with multiple platforms because <strong>you can’t even use platform-dependent objects in your shared code</strong>. You cannot use these objects because they are inaccessible.</p>

<p>As a result, it can be quite frustrating to integrate with platform-specific dependencies in multiplatform projects if you cannot recognize this limitation. In fact, <strong>this challenge is one of the most difficult to overcome with multiplatform programming</strong>.</p>

<p>Once you wrap your head around this concept (believe me, if I can do it, then I know you can!), you’re well on your way to mastering multiplatform development.</p>

<p>Overcoming this challenge benefits not only your multiplatform programming skills but also your general programming skills. You’ll also start to see how this can benefit your testing skills.</p>

<h2 id="step-2-define-the-platform-independent-interface">Step #2: Define the Platform-Independent Interface</h2>

<p>Your <strong>multiplatform interfaces</strong> define the responsibilities of your object and must be <strong>platform-independent</strong>.</p>

<p>In other words, the interface must <strong>only include</strong>:</p>
<ul>
  <li>platform-independent primitive types (strings, integers, floats, etc)</li>
  <li>types supported across all of your supported platforms (such as those defined in libraries with multiplatform support, for example <a href="https://github.com/Kotlin/kotlinx-datetime">kotlinx.datetime</a>), or</li>
  <li>objects composed only of these types</li>
</ul>

<p>Sometimes it’s easy to know when a type is platform-dependent, for example, anything in iOS beginning with “UI,” such as <code class="language-plaintext highlighter-rouge">UIApplication</code> or <code class="language-plaintext highlighter-rouge">UIViewController</code>. Sometimes this is more difficult to discern, like a <code class="language-plaintext highlighter-rouge">URL</code> or <code class="language-plaintext highlighter-rouge">UUID</code>.</p>

<p><em>(Note that this requirement also applies when defining <code class="language-plaintext highlighter-rouge">expect/actual</code> classes.)</em></p>

<h3 id="defining-our-platform-independent-haptics-interface">Defining Our (Platform-Independent) Haptics Interface</h3>

<p>Let’s say we want two different vibrations depending on the user’s action. Naming is hard, so I’ll leverage musical terminology to devise an appropriately named interface in this case. One haptic will be a shorter, more <a href="https://en.wikipedia.org/wiki/Staccato">staccato</a> style feedback, and another will be a slightly longer, more <a href="https://en.wikipedia.org/wiki/Marcato">marcato</a> style feedback. The interface might look like this:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kd">interface</span> <span class="nc">HapticFeedbackGenerator</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">staccatoFeedback</span><span class="p">()</span>
    <span class="k">fun</span> <span class="nf">marcatoFeedback</span><span class="p">()</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This interface is the <strong>high-level blueprint</strong>.</p>

<p>Let’s notice a few important points about this interface:</p>
<ul>
  <li>The interface only describes the object’s supported behaviors</li>
  <li>Nothing in this interface is dependent upon any platform details</li>
</ul>

<p>Thus, when working with this object in our code, there’s no need to indicate anything related to a platform. Instead, we invoke a function and expect it is handled appropriately within the platform-dependent code:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="nc">SomePresenter</span><span class="p">(</span><span class="o">..</span><span class="p">.)</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">didTapSomeButton</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// Handle the user interaction...</span>
        <span class="n">hapticFeedbackGenerator</span><span class="p">.</span><span class="nf">staccatoFeedback</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This example showcases the beauty of writing code in Kotlin Multiplatform: when writing code common to any platform, you don’t need to be concerned with the implementation details. Once you have written the platform-dependent <code class="language-plaintext highlighter-rouge">HapticFeedbackGenerator</code> classes, objects that conform to that interface can be used freely in shared code.</p>

<p>(Of course, this object can be used inside Swift, too, if you have a use case where you need haptics in iOS but not Android.)</p>

<h2 id="step-3-concrete-implementation-using-swift-for-ios">Step #3: Concrete Implementation using Swift for iOS</h2>

<p>In iOS, we can use two different classes that implement the <code class="language-plaintext highlighter-rouge">UIFeedbackGenerator</code> interface to give the user various kinds of haptic feedback.</p>

<p>We can initialize and prepare these generators in the initializer of our object so the feedback can be triggered when needed. Since we can instantiate these objects on their own, there’s no need to inject them into this class.</p>

<p><em>NOTE: This is just one example of how we could implement this. Haptic APIs differ depending on what version of iOS you are targeting.</em></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="kt">DarwinHapticFeedbackGenerator</span><span class="p">:</span> <span class="kt">HapticFeedbackGenerator</span> <span class="p">{</span>
  <span class="kd">private</span> <span class="k">let</span> <span class="nv">selectionFeedbackGenerator</span><span class="p">:</span> <span class="kt">UISelectionFeedbackGenerator</span>
  <span class="kd">private</span> <span class="k">let</span> <span class="nv">impactFeedbackGenerator</span><span class="p">:</span> <span class="kt">UIImpactFeedbackGenerator</span>

  <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">selectionFeedbackGenerator</span> <span class="o">=</span> <span class="kt">UISelectionFeedbackGenerator</span><span class="p">()</span>
    <span class="n">selectionFeedbackGenerator</span><span class="o">.</span><span class="nf">prepare</span><span class="p">()</span>

    <span class="n">impactFeedbackGenerator</span> <span class="o">=</span> <span class="kt">UIImpactFeedbackGenerator</span><span class="p">()</span>
    <span class="n">impactFeedbackGenerator</span><span class="o">.</span><span class="nf">prepare</span><span class="p">()</span>
  <span class="p">}</span>

  <span class="kd">func</span> <span class="nf">staccatoFeedback</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">selectionFeedbackGenerator</span><span class="o">.</span><span class="nf">selectionChanged</span><span class="p">()</span>
  <span class="p">}</span>

  <span class="kd">func</span> <span class="nf">marcatoFeedback</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">impactFeedbackGenerator</span><span class="o">.</span><span class="nf">impactOccurred</span><span class="p">()</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="new-up-and-useinject-in-your-ios-app">New-Up and Use/Inject in Your iOS App</h3>

<p>Our app likely has an object to manage user interactions. Therefore we can new up an instance of our <code class="language-plaintext highlighter-rouge">DarwinHapticFeedbackGenerator</code> and pass it in as needed:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="nv">hapticFeedbackGenerator</span> <span class="o">=</span> <span class="kt">DarwinHapticFeedbackGenerator</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">presenter</span> <span class="o">=</span> <span class="kt">SomePresenter</span><span class="p">(</span><span class="nv">hapticFeedbackGenerator</span><span class="p">:</span> <span class="n">hapticFeedbackGenerator</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="step-4-concrete-implementation-using-kotlin-for-android">Step #4: Concrete Implementation using Kotlin for Android</h2>

<p>As we saw above, the Android implementation <em>depends on</em> the <code class="language-plaintext highlighter-rouge">Window</code> object. Therefore, the <code class="language-plaintext highlighter-rouge">AndroidHapticsFeedbackGenerator</code> can take this dependency in the object’s constructor.</p>

<p>If you just thought to yourself, “isn’t this constructor dependency injection?” you’d be absolutely right! 👏🏻</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="nc">AndroidHapticsFeedbackGenerator</span><span class="p">(</span>
    <span class="k">private</span> <span class="kd">val</span> <span class="py">window</span><span class="p">:</span> <span class="nc">Window</span><span class="p">?</span>
<span class="p">)</span> <span class="p">:</span> <span class="nc">HapticFeedbackGenerator</span> <span class="p">{</span>
    <span class="k">override</span> <span class="k">fun</span> <span class="nf">staccatoFeedback</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">window</span>
            <span class="o">?.</span><span class="n">decorView</span>
            <span class="o">?.</span><span class="n">rootView</span>
            <span class="o">?.</span><span class="nf">performHapticFeedback</span><span class="p">(</span><span class="nc">HapticFeedbackConstants</span><span class="p">.</span><span class="nc">CLOCK_TICK</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">override</span> <span class="k">fun</span> <span class="nf">marcatoFeedback</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">window</span>
            <span class="o">?.</span><span class="n">decorView</span>
            <span class="o">?.</span><span class="n">rootView</span>
            <span class="o">?.</span><span class="nf">performHapticFeedback</span><span class="p">(</span><span class="nc">HapticFeedbackConstants</span><span class="p">.</span><span class="nc">CONTEXT_CLICK</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="new-up-and-useinject-in-your-android-app">New-Up and Use/Inject in Your Android App</h3>

<p>As with iOS, you’ll need to instantiate this in Kotlin within your application and inject it. Injecting the <code class="language-plaintext highlighter-rouge">Window</code> object we need from the <code class="language-plaintext highlighter-rouge">Activity</code> when creating this class allows us to invoke methods on it when needed.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kd">val</span> <span class="py">hapticFeedbackGenerator</span> <span class="p">=</span> <span class="nc">DefaultHapticsFeedbackGenerator</span><span class="p">(</span><span class="n">window</span><span class="p">)</span>
<span class="kd">val</span> <span class="py">presenter</span> <span class="p">=</span> <span class="nc">SomePresenter</span><span class="p">(</span><span class="n">hapticFeedbackGenerator</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can choose to create and inject your dependencies manually, or there are also DI frameworks, such as <a href="https://insert-koin.io/docs/reference/koin-mp/kmp/">Koin</a> and <a href="https://github.com/kosi-libs/Kodein">Kodein</a>, that you can consider.</p>

<h2 id="pro-tip-2-visualize-platform-dependent-objects-to-illuminate-relationships">Pro-Tip #2: Visualize Platform-Dependent Objects to Illuminate Relationships</h2>

<p>Hopefully, it’s clear from this example that your multiplatform concrete classes are a <strong>platform-dependent implementation</strong>.</p>

<p>As the Dependency Inversion Principle describes:</p>

<ul>
  <li>Depend on an interface abstraction (a high-level blueprint)</li>
  <li>The abstracted interface (high-level blueprint) is independent of the implementation details (the low-level components)</li>
  <li>Depend in the direction of stability</li>
</ul>

<p>Let’s draw a simple class diagram to illustrate this.</p>

<p>We have a <strong>platform-independent interface</strong> defined to manage haptics in our shared framework:</p>

<figure>
    <a href="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%201%20Interface%20Only.jpg">
        <img src="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%201%20Interface%20Only.jpg" alt="alternate text" />
    </a>
</figure>

<p>We’ll also have two implementations of this class: one for Android and one for Apple (Darwin) platforms:</p>

<figure>
    <a href="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%202%20interface%20and%20implementations.jpg">
        <img src="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%202%20interface%20and%20implementations.jpg" alt="alternate text" />
    </a>
</figure>

<p>Need a quick review of reading UML class diagrams?</p>
<ul>
  <li>The white arrow head points from a concrete class to the interface it implements. You can read this arrow as: “is a.”</li>
  <li>For example:
    <ul>
      <li>“The <code class="language-plaintext highlighter-rouge">AndroidHapticFeedbackGenerator</code> <strong>is a</strong> <code class="language-plaintext highlighter-rouge">HapticFeedbackGenerator</code>.”</li>
      <li>“The <code class="language-plaintext highlighter-rouge">DarwinHapticFeedbackGenerator</code> <strong>is a</strong> <code class="language-plaintext highlighter-rouge">HapticFeedbackGenerator</code>.”</li>
    </ul>
  </li>
</ul>

<p><br /></p>

<p>The objects needed to implement the concrete classes are dependent upon platform-specific APIs. We want to honor encapsulation, so these will be private for each implementation. These are the low-level components. Let’s add these to the diagram to see how this would look:</p>

<figure>
    <a href="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%203%20platform-dependent%20apis.jpg">
        <img src="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%203%20platform-dependent%20apis.jpg" alt="alternate text" />
    </a>
</figure>

<p>Need a quick review of reading UML class diagrams?</p>
<ul>
  <li>The solid black arrow points from an object to an object it holds an instance of. You can read this arrow as: “has a.”</li>
  <li>For example:
    <ul>
      <li>“The <code class="language-plaintext highlighter-rouge">AndroidHapticFeedbackGenerator</code> <strong>has a</strong> <code class="language-plaintext highlighter-rouge">Window</code>.”</li>
      <li>“The <code class="language-plaintext highlighter-rouge">DarwinHapticFeedbackGenerator</code> <strong>has a</strong> <code class="language-plaintext highlighter-rouge">UISelectionFeedbackGenerator</code> and <strong>has a</strong> <code class="language-plaintext highlighter-rouge">UIImpactFeedbackGenerator</code>.”</li>
    </ul>
  </li>
</ul>

<p><br /></p>

<p>Any object can use our <code class="language-plaintext highlighter-rouge">HapticFeedbackGenerator</code> in our shared framework, such as <code class="language-plaintext highlighter-rouge">SomePresenter</code>, simply by injecting a concrete implementation. And <code class="language-plaintext highlighter-rouge">SomePresenter</code> doesn’t need to be concerned about platform-specific APIs.</p>

<p>In the following diagram, <code class="language-plaintext highlighter-rouge">SomePresenter</code> <strong>has a</strong> <code class="language-plaintext highlighter-rouge">HapticFeedbackGenerator</code>.</p>

<figure>
    <a href="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%204%20using%20shared%20interface.jpg">
        <img src="/assets/images/kmm/di-dip%20for%20shared%20code%20-%20uml%204%20using%20shared%20interface.jpg" alt="alternate text" />
    </a>
</figure>

<p>Take note of the direction the arrows are pointing and what is pointing to what. UML class diagrams are a great tool to visualize dependencies between objects.</p>

<h2 id="comprehending-the-dip">Comprehending the DIP</h2>

<p>Another way I like to think about the DIP is “to depend on that which provides stability.” In our case, the <strong>high-level blueprint</strong>, which we have created and is entirely within our control, is stable because <em>we</em> have defined it.</p>

<p>To deepen our comprehension, we can also say the opposite: “do not depend on that which does not provide stability.” The low-level components, in our case being platform-specific APIs, are entirely outside our control. If we were to depend upon these platform-specific APIs in our abstract blueprint, any changes to these platform APIs would impact our blueprint.</p>

<p>“But what happens when Google or Apple changes an API we depend on?” you might ask. Naturally, the respective concrete implementation that satisfies the interface will need to change. However, anything outside of that scope is under the protection of the interface.</p>

<h2 id="revisiting-the-solution-to-platform-dependent-apis">Revisiting the Solution to Platform-Dependent APIs</h2>

<p>Earlier, we asked: “How do I handle platform-dependent APIs?” and answered with the following:</p>

<blockquote>
  <p>Inject <strong>platform-dependent objects</strong><br />
into <strong>concrete instances</strong> <br />
conforming to a <strong>platform-independent interface</strong></p>
</blockquote>

<p>In the haptics example, we are:</p>
<blockquote>
  <p>injecting a <strong><code class="language-plaintext highlighter-rouge">Window</code></strong> (a platform-dependent object)<br />
into an <strong><code class="language-plaintext highlighter-rouge">AndroidHapticFeedbackGenerator</code></strong> (a concrete instance)<br /> 
conforming to the <strong><code class="language-plaintext highlighter-rouge">HapticFeedbackGenerator</code></strong> (platform-independent) interface</p>
</blockquote>

<p>This example illustrates how we isolate a platform dependency to the smallest possible surface area.</p>

<h2 id="tradeoffs">Tradeoffs</h2>

<p>The primary benefit of isolating platform-dependent code behind a platform-independent interface is any code that utilizes these components can be oblivious to platform-specific details and thus shared throughout the codebase.</p>

<p>Of course, a natural result is the added indirection when working with these components. This is a reasonable tradeoff, given the benefit of supporting multiple platforms. Additionally, the more limited and isolated the platform-dependent code is, the easier it is to maintain and troubleshoot.</p>

<p>If something were to change within Apple or Google’s haptics APIs, we would only have a single location that would need to be updated. Therefore, the rest of our application code is protected from these changes.</p>

<h2 id="summarizing">Summarizing</h2>

<ul>
  <li>We created a platform-independent interface, the <em>high-level blueprint</em>, for how we want our application to interact with haptics.</li>
  <li>We defined platform-specific Android and iOS concrete class implementations that utilize platform-specific APIs. These are the <em>low-level components</em>.</li>
  <li>These concrete platform-specific implementations are injected into the object(s) that need to use them and can be called from shared code without concern about which platform uses it.</li>
  <li>Understanding how to employ the Dependency Injection (DI) technique and applying the SOLID Dependency Inversion Principle (DIP) are critical to isolating platform dependencies.</li>
  <li>Drawing UML class diagrams to illustrate relationships between these objects is a valuable tool to deepen our understanding of how these objects relate to each other.</li>
</ul>

<p>Would you like to see more real-world examples of isolating platform dependencies? Do you have unresolved challenges with Kotlin Multiplatform development? Would more examples of dependency injection or dependency inversion be useful? Let me know how I can help. 👍🏻</p>]]></content><author><name>Derek Lee</name></author><category term="Science" /><category term="Kotlin Multiplatform" /><category term="Dependency Injection" /><category term="Dependency Inversion Principle" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Why iOS Engineers Should Avoid This Glorified KMM Technique</title><link href="/science/avoid-this-kmm-technique/" rel="alternate" type="text/html" title="Why iOS Engineers Should Avoid This Glorified KMM Technique" /><published>2022-09-22T00:00:00+00:00</published><updated>2022-09-22T00:00:00+00:00</updated><id>/science/avoid-this-kmm-technique</id><content type="html" xml:base="/science/avoid-this-kmm-technique/"><![CDATA[<h1 id="tldr">TL;DR</h1>
<ul>
  <li>If you’re an iOS engineer who wants to build multiplatform apps using KMM, the few benefits of using the <code class="language-plaintext highlighter-rouge">expect/actual</code> syntax do not outweigh those of writing your platform-dependent code in Swift.</li>
  <li>The use-case for iOS engineers to consider leveraging <code class="language-plaintext highlighter-rouge">expect/actual</code> syntax would be when building a multiplatform framework.</li>
  <li>If you’re going to use <code class="language-plaintext highlighter-rouge">expect/actual</code>, be sure to reference Apple’s Objective-C documentation over Swift documentation and use the Kotlin/Native headers for the most accurate representation of the iOS APIs available in Kotlin.</li>
</ul>

<p><br /></p>
<h1 id="the-expectactual-syntax-of-kotlin-multiplatform-mobile-kmm">The <code class="language-plaintext highlighter-rouge">expect/actual</code> Syntax of Kotlin Multiplatform Mobile (KMM)</h1>

<p><a href="https://kotlinlang.org/docs/multiplatform-connect-to-apis.html">The Kotlin Multiplatform SDK includes a syntactical construct integrated into JetBrains IDEs</a> that engineers can use to define classes and functions that are <em>expect</em> -ed (pun intended) to have platform-specific implementations. The <strong>actual</strong> implementations are also written in Kotlin separately for Android and iOS.</p>

<p>When looking at the code modules in a KMM project: within the KMM shared framework module, you first define a class or a function as <em>expected</em>. Then the <em>actual</em> implementations are written for each supported platform module. The following example illustrates what module the code is defined within for Android and iOS:</p>

<figure>
    <a href="/assets/images/kmm/KMM Code Org - expect actual.jpg">
        <img src="/assets/images/kmm/KMM Code Org - expect actual.jpg" alt="alternate text" />
    </a>
    <figcaption>The `common` module defines the expected classes and functions, and platform modules define the actual implementation.</figcaption>
</figure>

<p>We looked at some simple examples <a href="/science/kmm-for-ios-engineers/" target="_blank">in the last blog</a>. These examples are helpful because they allow us to wrap our heads around the concept before diving into something more complicated.</p>

<p>I want to take you on a journey of writing some code using this approach to illustrate how this can become more complicated in practice than expected.</p>

<p>In fact, I’m going to make a bold statement and propose that there’s only a <strong>single scenario</strong> where you, the iOS Engineer, should even consider using the <code class="language-plaintext highlighter-rouge">expect</code>/<code class="language-plaintext highlighter-rouge">actual</code> syntax.</p>

<p><br /></p>
<h2 id="this-post-is-part-of-a-series-on-kotlin-multiplatform"><em>This post is part of a series on Kotlin Multiplatform:</em></h2>
<ol>
  <li><a href="/science/kmm-for-ios-engineers/" target="_blank"><em>The iOS Engineer’s Guide to Beginning Kotlin Multiplatform Development</em></a></li>
  <li><em>Why iOS Engineers Should Avoid This Glorified KMM Technique</em></li>
</ol>

<p><br /></p>

<h1 id="case-study-1-the-hello-world-of-kmm">Case Study #1: The “Hello World!” of KMM</h1>

<p>This example is included in new KMM projects and confirms the setup of your development environment is correct by ensuring your Android app and iOS app can integrate appropriately with the shared KMM framework.</p>

<h2 id="common-module-expect-declaration">Common Module <code class="language-plaintext highlighter-rouge">expect</code> declaration</h2>

<p>The <code class="language-plaintext highlighter-rouge">Platform</code> class defines a single property called <code class="language-plaintext highlighter-rouge">platform</code>, and returns a string on all supported platforms.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="n">expect</span> <span class="kd">class</span> <span class="nc">Platform</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">val</span> <span class="py">platform</span><span class="p">:</span> <span class="nc">String</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="androidmain-module-actual-implementation">androidMain Module <code class="language-plaintext highlighter-rouge">actual</code> implementation</h2>

<p>For Android, the platform string indicates the platform is Android along with the SDK version number.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">Platform</span> <span class="n">actual</span> <span class="k">constructor</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">actual</span> <span class="kd">val</span> <span class="py">platform</span><span class="p">:</span> <span class="nc">String</span> <span class="p">=</span> <span class="s">"Android ${android.os.Build.VERSION.SDK_INT}"</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><em>Important: Given that this is the “Hello World!” of KMM, I include the Android implementation here for thoroughness. However, for the remainder of the examples, I will omit the actual Android implementation as it’s unrelated to the primary goal of this post: to illustrate the tradeoffs involved in using <code class="language-plaintext highlighter-rouge">expect/actual</code> for writing the platform-dependent iOS code.</em></p>

<h2 id="iosmain-module-actual-implementation">iosMain Module <code class="language-plaintext highlighter-rouge">actual</code> Implementation</h2>

<p>For iOS, we can use the Foundation class of UIDevice, which provides access to the device’s <code class="language-plaintext highlighter-rouge">systemName</code> and <code class="language-plaintext highlighter-rouge">systemVersion</code> properties.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="nn">platform.UIKit.UIDevice</span>

<span class="n">actual</span> <span class="kd">class</span> <span class="nc">Platform</span> <span class="n">actual</span> <span class="k">constructor</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">actual</span> <span class="kd">val</span> <span class="py">platform</span><span class="p">:</span> <span class="nc">String</span> <span class="p">=</span> <span class="nc">UIDevice</span><span class="p">.</span><span class="n">currentDevice</span><span class="p">.</span><span class="n">systemName</span> <span class="p">+</span> <span class="s">" "</span> 
        <span class="p">+</span> <span class="nc">UIDevice</span><span class="p">.</span><span class="n">currentDevice</span><span class="p">.</span><span class="n">systemVersion</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Like any example of “Hello World!”, this is the simplest use case illustrating how you can write platform-dependent code for two platforms (Android and iOS) using the <code class="language-plaintext highlighter-rouge">expect/actual</code> syntax.</p>

<h3 id="writing-all-of-your-code-in-kotlin">Writing all of your code in Kotlin</h3>

<p>As you likely noticed, you get to write all of this code in Kotlin! This is the main benefit of leveraging the <code class="language-plaintext highlighter-rouge">expect/actual</code> syntax. In addition, I find Kotlin delightful to program in with its support for object-oriented and functional programming styles, its modern syntax, tight integration with modern IDEs (Android Studio and IntelliJ), and what I perceive to be highly active support from JetBrains and the community.</p>

<p>Although I would argue that switching from one programming language to another in the context of full-stack development and pair programming doesn’t carry a heavy burden, objectively speaking, being able to write all of your platform-dependent code in a single language does mean less context-switching for the author.</p>

<h3 id="what-would-this-look-like-in-swift">What would this look like in Swift?</h3>

<p>If we were to have written the above code in Swift, it would look surprisingly similar:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">UIDevice</span><span class="o">.</span><span class="n">current</span><span class="o">.</span><span class="n">systemName</span> <span class="o">+</span> <span class="s">" "</span> <span class="o">+</span> <span class="kt">UIDevice</span><span class="o">.</span><span class="n">current</span><span class="o">.</span><span class="n">systemVersion</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Can you spot any differences between this and the Kotlin version above? 🤔</p>

<p><br /></p>

<h1 id="case-study-2-persisting-simple-data-structures">Case Study #2: Persisting Simple Data Structures</h1>

<p>One of the most common tasks for mobile engineers is data persistence, and <code class="language-plaintext highlighter-rouge">UserDefaults</code> is often a common approach for saving simple data structures.</p>

<p>In this case, we will start with how we might write this code in Swift and abstract a familiar interface to use with <code class="language-plaintext highlighter-rouge">expect/actual</code>.</p>

<p><em>NOTE: In a real-life example, before taking concrete code and abstracting it to a generic interface, it’s prudent to look at all platforms that need to be supported before crafting that interface. Are you interested in seeing detailed examples of how to do this? <a href="/contact/">Let me know!</a></em></p>

<p>In Swift if we wanted to <strong>save</strong> a string value to user defaults, it might look like this:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">UserDefaults</span><span class="o">.</span><span class="n">standard</span><span class="o">.</span><span class="nf">set</span><span class="p">(</span><span class="s">"Some value"</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="s">"some-key"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Likewise, <strong>retrieving</strong> that data might be something like:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="nv">someValue</span> <span class="o">=</span> <span class="kt">UserDefaults</span><span class="o">.</span><span class="n">standard</span><span class="o">.</span><span class="nf">string</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="s">"some-key"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s use <code class="language-plaintext highlighter-rouge">expect/actual</code> to implement something similar in KMM.</p>

<h2 id="common-module-expect-declaration-1">Common Module <code class="language-plaintext highlighter-rouge">expect</code> declaration</h2>

<p>Starting with the <code class="language-plaintext highlighter-rouge">expect</code> declaration, this acts as the interface that we <em>expect</em> each platform to implement.</p>

<p>There are naturally a variety of ways we can choose how to organize and save data. However, for the sake of simplicity, we’ll use saving and retrieving a string.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">expect</span> <span class="kd">class</span> <span class="nc">LocalPersistence</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">save</span><span class="p">(</span><span class="n">string</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span>
    <span class="k">fun</span> <span class="nf">get</span><span class="p">(</span><span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">):</span> <span class="nc">String</span><span class="p">?</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="iosmain-module-actual-implementation-1">iosMain Module <code class="language-plaintext highlighter-rouge">actual</code> Implementation</h2>

<p>For iOS, instead of re-typing the methods defined in the interface, let’s make the most of the IDE’s tight integration.</p>

<p>Writing out just the actual class declaration…</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocalPersistence</span> <span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>… shows the familiar red underline on the <code class="language-plaintext highlighter-rouge">LocalPersistence</code> class name. A swift stroke of <code class="language-plaintext highlighter-rouge">⌥ + ↵</code> (Option+Enter) reveals the “Add missing actual members” option:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - Add missing actual members.png">
        <img src="/assets/images/kmm/expectactual - Add missing actual members.png" alt="alternate text" />
    </a>
</figure>

<p>Selecting this will automatically populate our class with the function declarations defined in the expected “interface”:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocalPersistence</span> <span class="p">{</span>
    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">save</span><span class="p">(</span><span class="n">string</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span>
    <span class="p">}</span>

    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">get</span><span class="p">(</span><span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">):</span> <span class="nc">String</span><span class="p">?</span> <span class="p">{</span>
        <span class="nc">TODO</span><span class="p">(</span><span class="s">"Not yet implemented"</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="-ide-integration-supports-expectactual">+ IDE-Integration Supports <code class="language-plaintext highlighter-rouge">expect/actual</code></h3>

<p>Here we can introduce another benefit of this approach: support for <code class="language-plaintext highlighter-rouge">expect/actual</code> is baked right into the IDE (thanks to the <a href="https://kotlinlang.org/docs/multiplatform-mobile-plugin-releases.html#release-details">Kotlin Multiplatform Mobile Plugin</a>). So if you’re missing an implementation somewhere, the IDE will let you know, and assuming you have set up your project correctly, it’s possible to leverage the IDE to help create the actual function/class declaration.</p>

<h3 id="writing-ios-platform-dependent-code-in-kotlin">Writing iOS-Platform Dependent Code in Kotlin</h3>

<p>Let’s start by implementing the <code class="language-plaintext highlighter-rouge">save()</code> method of our actual implementation. First, we type <code class="language-plaintext highlighter-rouge">UserDefaults</code> to begin, as we already know from the Swift code that this is the object we want to use.</p>

<p>As expected, the IDE finds the class that we’re looking for.</p>

<figure>
    <a href="/assets/images/kmm/expectactual - UserDefaults Code Completion.png">
        <img src="/assets/images/kmm/expectactual - UserDefaults Code Completion.png" alt="alternate text" />
    </a>
</figure>

<p>Well, kind of.</p>

<p>Oh! That’s right.</p>

<p><em>NS</em>-UserDefaults!</p>

<p>Hm. I thought Swift dropped the ‘NS’ from the Foundation classes <a href="https://github.com/apple/swift-evolution/blob/main/proposals/0086-drop-foundation-ns.md">a while ago</a>, didn’t they?</p>

<p>Ok, so <code class="language-plaintext highlighter-rouge">NSUserDefaults.standard</code>…</p>

<figure>
    <a href="/assets/images/kmm/expectactual - NSUD standard Code Completion.png">
        <img src="/assets/images/kmm/expectactual - NSUD standard Code Completion.png" alt="alternate text" />
    </a>
</figure>

<p>Ah! Yes, yes. <em><code class="language-plaintext highlighter-rouge">standardUserDefaults</code></em>!</p>

<p>Wait. <br />
A.<br />
Second.<br /></p>

<p>This doesn’t seem right. The Swift API that we called above was <code class="language-plaintext highlighter-rouge">UserDefaults.standard</code>. I clearly remember migrating Swift code from one version to another when all the APIs suddenly become much more readable. So what’s going on here?</p>

<blockquote>
  <p>Surprise! Writing KMM code for iOS uses Objective-C APIs, not Swift APIs. 😱</p>
</blockquote>

<p>When writing platform-dependent code for iOS using KMM, at least for now, you’ll be integrating with the old Objective-C APIs. That means sometimes slight differences between what is possible, and sometimes major differences such as missing APIs that are not available in Objective-C. With Swift interoperability having been recently <a href="https://kotlinlang.org/docs/roadmap.html#removed-items">removed from the Kotlin Roadmap</a>, we’ll have to <a href="https://bit.ly/3BPy3UI">keep an eye on their progress</a> to see how this evolves in the future.</p>

<p>It might be a smooth transition if you’ve programmed in Objective-C before and understand the APIs and some lower-level aspects of the C language, such as pointers and memory allocation. However, this could be a stretch if you’ve only programmed in Swift or have yet to experience a language operating at a lower level than Swift.</p>

<p>All those improvements to the Swift language over the last few years…</p>

<p>Yup, that’s right.</p>

<p>😅</p>

<p>Wait, what about the <a href="https://developer.apple.com/documentation/swift/codable"><code class="language-plaintext highlighter-rouge">Codable</code> protocol</a>?</p>

<p>😭</p>

<p><em>(It’s a bummer that you can’t use the <code class="language-plaintext highlighter-rouge">Codable</code> protocol in Kotlin/Native, but it’s OK because there’s an even better way to share this kind of code.)</em></p>

<p>While it’s not <em>impossible</em> to leverage Swift-only APIs from a shared Kotlin/Native framework, it does require quite a bit of complicated tooling to access these in KMM via a <a href="https://medium.com/kodein-koders/create-a-kotlin-multiplatform-library-with-swift-1a818b2dc1b0">static Swift Library</a>.</p>

<p>Aaaaand we march on…</p>

<p>Time to save the string to <code class="language-plaintext highlighter-rouge">NSUserDefaults</code>. No biggie, right?</p>

<figure>
    <a href="/assets/images/kmm/expectactual - NSUD set Code Completion.png">
        <img src="/assets/images/kmm/expectactual - NSUD set Code Completion.png" alt="alternate text" />
    </a>
</figure>

<p>There’s no method to set a string in iOS (interestingly, <a href="https://developer.android.com/reference/kotlin/android/content/SharedPreferences.Editor#putString(kotlin.String,%20kotlin. string)">unlike Android</a>), but at least the Objective-C APIs match those that are in Swift. We can use <code class="language-plaintext highlighter-rouge">setObject</code> to save a string value for the given key.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocalPersistence</span> <span class="p">{</span>
    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">save</span><span class="p">(</span><span class="n">string</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span>
        <span class="nc">NSUserDefaults</span><span class="p">.</span><span class="n">standardUserDefaults</span><span class="p">.</span><span class="nf">setObject</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="o">..</span><span class="p">.</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Great! Now onto retrieval. Thankfully, this pretty much matches what we would expect and completes our implementation on iOS:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocalPersistence</span> <span class="p">{</span>
    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">save</span><span class="p">(</span><span class="n">string</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span>
        <span class="nc">NSUserDefaults</span><span class="p">.</span><span class="n">standardUserDefaults</span><span class="p">.</span><span class="nf">setObject</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">get</span><span class="p">(</span><span class="n">key</span><span class="p">:</span> <span class="nc">String</span><span class="p">):</span> <span class="nc">String</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">NSUserDefaults</span><span class="p">.</span><span class="n">standardUserDefaults</span><span class="p">.</span><span class="nf">stringForKey</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="pro-tip-1-when-writing-kmm-code-for-ios-using-expectactual-reference-apples-objective-c-not-swift-api-documentation">Pro-Tip #1: When writing KMM code for iOS using expect/actual, reference Apple’s Objective-C (not Swift)! API documentation</h3>

<p>Given that KMM code integrates with the Objective-C framework APIs, your best resource is to reference the Objective-C(not Swift!) API documentation. <a href="https://stackoverflow.com/q/73308682/1470581">This will solve a lot of your initial struggles</a> with writing Kotlin/Native code for iOS.</p>

<p>Apple makes this easy for all of their online documentation references with a drop-down to change the language:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - Apple Documentation Language Options.png">
        <img src="/assets/images/kmm/expectactual - Apple Documentation Language Options.png" alt="alternate text" />
    </a>
</figure>

<p><br /></p>

<h1 id="case-study-3-getting-the-users-current-location">Case Study #3: Getting the user’s current location</h1>

<p>Another everyday use case for mobile developers is getting the user’s current location. Again, we’ll keep things simple by exploring only the prominent use cases: getting permission to acquire a user’s location and retrieving the user’s location.</p>

<p>Let’s start with the Swift code to <strong>request user permission to access their location</strong>:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="nv">locationManager</span> <span class="o">=</span> <span class="kt">CLLocationManager</span><span class="p">()</span>
<span class="n">locationManager</span><span class="o">.</span><span class="nf">requestWhenInUseAuthorization</span><span class="p">()</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once the user has granted us the ability to access this date, <strong>requesting the user’s current location</strong> might look like this:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span>
    <span class="kt">CLLocationManager</span><span class="o">.</span><span class="nf">authorizationStatus</span><span class="p">()</span> <span class="o">==</span> <span class="o">.</span><span class="n">authorizedWhenInUse</span> <span class="o">||</span>
    <span class="kt">CLLocationManager</span><span class="o">.</span><span class="nf">authorizationStatus</span><span class="p">()</span> <span class="o">==</span> <span class="o">.</span><span class="n">authorizedAlways</span>
<span class="p">)</span> <span class="p">{</span>
    <span class="k">let</span> <span class="nv">coordinate</span> <span class="o">=</span> <span class="n">locationManager</span><span class="o">.</span><span class="n">location</span><span class="p">?</span><span class="o">.</span><span class="n">coordinate</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">location</code> property of type <code class="language-plaintext highlighter-rouge">CLLocation</code> contains the <code class="language-plaintext highlighter-rouge">coordinate</code> property of type <a href="https://developer.apple.com/documentation/corelocation/cllocationcoordinate2d"><code class="language-plaintext highlighter-rouge">CLLocationCoordinate2D</code></a>. This then exposes latitude and longitude as parameters:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - CLLocationCoordinate2D.png">
        <img src="/assets/images/kmm/expectactual - CLLocationCoordinate2D.png" alt="alternate text" />
    </a>
</figure>

<p>And <a href="https://developer.apple.com/documentation/corelocation/cllocationdegrees"><code class="language-plaintext highlighter-rouge">CLLocationDegrees</code></a> is simply a type alias for a Double:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - CLLocationDegrees.png">
        <img src="/assets/images/kmm/expectactual - CLLocationDegrees.png" alt="alternate text" />
    </a>
</figure>

<p>Great! Now we have an idea of what this might look like to help inform our interface definition… at least for iOS.</p>

<p><em>Note: We could generalize this for the single-use case we have in iOS now, only to learn later that Android approaches solving this problem quite differently. As mentioned previously, generalizing to a platform-independent interface requires additional consideration, and for the sake of this example, I will only focus on the iOS use case.</em></p>

<h2 id="common-module-expect-declaration-2">Common Module <code class="language-plaintext highlighter-rouge">expect</code> declaration</h2>

<p>We can define the expected “interface” for our use case based on the iOS API:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">expect</span> <span class="kd">class</span> <span class="nc">PhysicalLocationServices</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">requestPermissions</span><span class="p">()</span>
    <span class="k">fun</span> <span class="nf">currentLocation</span><span class="p">():</span> <span class="nc">PhysicalLocation</span><span class="p">?</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Since we’ll return a user’s <code class="language-plaintext highlighter-rouge">PhysicalLocation</code>, let’s define a data class to hold that data:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kd">data class</span> <span class="nc">PhysicalLocation</span><span class="p">(</span>
    <span class="kd">val</span> <span class="py">longitude</span><span class="p">:</span> <span class="nc">Double</span><span class="p">,</span>
    <span class="kd">val</span> <span class="py">latitude</span><span class="p">:</span> <span class="nc">Double</span><span class="p">,</span>
<span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="iosmain-module-actual-implementation-2">iosMain Module <code class="language-plaintext highlighter-rouge">actual</code> Implementation</h2>

<h3 id="requesting-permission-for-location-data">Requesting permission for location data</h3>

<p>Requesting permissions in Objective-C closely matches the same in Swift. One might keep the <code class="language-plaintext highlighter-rouge">locationManager</code> as a property (line #2), and the same API <code class="language-plaintext highlighter-rouge">requestWhenInUseAuthorization()</code> can be called to request permissions (line #5):</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocationServices</span> <span class="p">{</span>
    <span class="k">private</span> <span class="kd">val</span> <span class="py">locationManager</span> <span class="p">=</span> <span class="nc">CLLocationManager</span><span class="p">()</span>

    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">requestPermission</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">locationManager</span><span class="p">.</span><span class="nf">requestWhenInUseAuthorization</span><span class="p">()</span>
    <span class="p">}</span>

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

<h3 id="requesting-the-users-location">Requesting the user’s location</h3>

<p>The first step in checking for the user’s location is to confirm that the user has given authorization for the type of permission we expect.</p>

<p>This is an excellent example of an API that seems straightforward, but in this case, <a href="https://stackoverflow.com/q/73274459/1470581">is a bit tricky to find</a> because these constants differ slightly between Swift and Objective-C:</p>

<table>
  <thead>
    <tr>
      <th>Swift</th>
      <th> </th>
      <th>Objective-C</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>.notDetermined</td>
      <td>→</td>
      <td>kCLAuthorizationStatusNotDetermined</td>
    </tr>
    <tr>
      <td>.restricted</td>
      <td>→</td>
      <td>kCLAuthorizationStatusRestricted</td>
    </tr>
    <tr>
      <td>.denied</td>
      <td>→</td>
      <td>kCLAuthorizationStatusDenied</td>
    </tr>
    <tr>
      <td>.authorizedAlways</td>
      <td>→</td>
      <td>kCLAuthorizationStatusAuthorizedAlways</td>
    </tr>
    <tr>
      <td>.authorizedWhenInUse</td>
      <td>→</td>
      <td>kCLAuthorizationStatusAuthorizedWhenInUse</td>
    </tr>
  </tbody>
</table>

<p>The easiest way to find this difference is to reference the Objective-C documentation mentioned above. However, if you’re already in the Android Studio IDE and want to stay in that environment, you can also dig through the Kotlin code.</p>

<h3 id="pro-tip-2-all-ios-framework-objective-c-api-headers-are-accessible-in-kotlin">Pro-Tip #2: All iOS framework Objective-C API headers are accessible in Kotlin</h3>

<p>The fastest way to get into these headers is to navigate in the IDE directly to the definition of any object you’re already using (for example, <code class="language-plaintext highlighter-rouge">requestWhenInUseAuthorization()</code>) via <code class="language-plaintext highlighter-rouge">⌥ + ⌘ + B</code> (or right-click, <em>Go To</em> → <em>implementation(s)</em>).</p>

<figure>
    <a href="/assets/images/kmm/expectactual - Go To Implementations.png">
        <img src="/assets/images/kmm/expectactual - Go To Implementations.png" alt="alternate text" />
    </a>
</figure>

<p>This takes you directly to the definition of the API:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - requestWhenInUse Declaration.png">
        <img src="/assets/images/kmm/expectactual - requestWhenInUse Declaration.png" alt="alternate text" />
    </a>
</figure>

<p>… where you can then search through to find what you might be looking for:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - Digging Through Kotlin APIs.png">
        <img src="/assets/images/kmm/expectactual - Digging Through Kotlin APIs.png" alt="alternate text" />
    </a>
</figure>

<p>This helps us to write the first check to ensure proper permissions to gather location:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocationServices</span> <span class="p">{</span>
    <span class="o">..</span><span class="p">.</span>
    
    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">currentLocation</span><span class="p">():</span> <span class="nc">PhysicalLocation</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">locationManager</span><span class="p">.</span><span class="n">authorizationStatus</span> <span class="p">==</span> <span class="n">kCLAuthorizationStatusAuthorizedWhenInUse</span> <span class="p">||</span>
            <span class="n">locationManager</span><span class="p">.</span><span class="n">authorizationStatus</span> <span class="p">==</span> <span class="n">kCLAuthorizationStatusAuthorizedAlways</span>
        <span class="p">)</span> <span class="p">{</span>
            
        <span class="p">}</span>

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

<p>The next step is to get the latitude and longitude values of the location. Simple, right?</p>

<p>As we saw above with Swift, <code class="language-plaintext highlighter-rouge">locationManager.location.coordinate</code> should return a <code class="language-plaintext highlighter-rouge">CLLocationCoordinate2D</code> object where we can access the latitude and longitude values:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - Looking for CLLocationCoordinate2D.png">
        <img src="/assets/images/kmm/expectactual - Looking for CLLocationCoordinate2D.png" alt="alternate text" />
    </a>
</figure>

<p>Interesting.</p>

<p>There <em>is</em> a <code class="language-plaintext highlighter-rouge">CLLocationCoordinate2D</code> object, but it’s wrapped in a <code class="language-plaintext highlighter-rouge">CValue</code> object.</p>

<p>What is a <code class="language-plaintext highlighter-rouge">CValue</code> object?</p>

<p>If we take a look at the Objective-C documentation for <code class="language-plaintext highlighter-rouge">CLLocationCoordinate2D</code>, we can see that <a href="https://developer.apple.com/documentation/corelocation/cllocationcoordinate2d?language=objc">this is a C-struct</a> (<em>not to be mistaken for a Swift struct!</em>):</p>

<figure>
    <a href="/assets/images/kmm/expectactual - CLLocationCoordinate2D Defined.png">
        <img src="/assets/images/kmm/expectactual - CLLocationCoordinate2D Defined.png" alt="alternate text" />
    </a>
</figure>

<p>… and the Kotlin/Native header files shows the return type as a <code class="language-plaintext highlighter-rouge">kotlinx.cinterop.CValue</code>:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - CLLocationCoordinate2D Header Declaration.png">
        <img src="/assets/images/kmm/expectactual - CLLocationCoordinate2D Header Declaration.png" alt="alternate text" />
    </a>
</figure>

<p>The <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/-c-value/">documentation on CValue</a> is thin and IMHO not very easy to understand, though it appears as though the <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/use-contents.html"><code class="language-plaintext highlighter-rouge">useContents</code></a> method could be used to access the data:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - CValue useContents.png">
        <img src="/assets/images/kmm/expectactual - CValue useContents.png" alt="alternate text" />
    </a>
</figure>

<p>This gives us the final implementation to gather this data, including some handling in case the value is null:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="n">actual</span> <span class="kd">class</span> <span class="nc">LocationServices</span> <span class="p">{</span>
    <span class="o">..</span><span class="p">.</span>
    
    <span class="n">actual</span> <span class="k">fun</span> <span class="nf">currentLocation</span><span class="p">():</span> <span class="nc">PhysicalLocation</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">locationManager</span><span class="p">.</span><span class="n">authorizationStatus</span> <span class="p">==</span> <span class="n">kCLAuthorizationStatusAuthorizedWhenInUse</span> <span class="p">||</span>
            <span class="n">locationManager</span><span class="p">.</span><span class="n">authorizationStatus</span> <span class="p">==</span> <span class="n">kCLAuthorizationStatusAuthorizedAlways</span>
        <span class="p">)</span> <span class="p">{</span>
            <span class="n">locationManager</span><span class="p">.</span><span class="n">location</span><span class="o">?.</span><span class="n">coordinate</span><span class="o">?.</span><span class="nf">useContents</span> <span class="p">{</span>
                <span class="k">return</span> <span class="nc">PhysicalLocation</span><span class="p">(</span><span class="n">latitude</span><span class="p">,</span> <span class="n">longitude</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">}</span>

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

<p>Although it’s not clear in the code sample above, the IDE helps us to understand what <code class="language-plaintext highlighter-rouge">useContents</code> is giving us by showing that it is, in fact, a <code class="language-plaintext highlighter-rouge">CLLocationCoordinate2D</code> object. A screenshot shows the hint given by the IDE that <code class="language-plaintext highlighter-rouge">this</code> is of type <code class="language-plaintext highlighter-rouge">CLLocationCoordinate2D</code>:</p>

<figure>
    <a href="/assets/images/kmm/expectactual - IDE Assistance for useContents.png">
        <img src="/assets/images/kmm/expectactual - IDE Assistance for useContents.png" alt="alternate text" />
    </a>
</figure>

<h3 id="reflecting">Reflecting</h3>

<p>As you can see with this example, we’re not just dealing with Objective-C APIs over Swift APIs but also with how Objective-C manages memory.</p>

<p>As with many Objective-C APIs, this involves interacting with C-level APIs and objects. Even though these constructs are exposed within Kotlin/Native through the <code class="language-plaintext highlighter-rouge">kotlinx.cinterop</code> package, <a href="https://stackoverflow.com/q/73193792/1470581">they can be confusing</a> to use and <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/">have very thin documentation</a>. A foundational understanding of C- and Objective-C concepts is a pre-requite to ensure you interact with these constructs safely.</p>

<p><br /></p>

<h1 id="on-practicality">On Practicality</h1>

<p>As an iOS engineer whose goal is to more easily share code between iOS and Android to simplify how I can expand my app footprint to additional users, based on the limitations and complexities of using <code class="language-plaintext highlighter-rouge">expect/actual</code>, <strong>I honestly cannot recommend this approach for sharing platform-dependent code in KMM.</strong></p>

<p><br /></p>

<h1 id="what-about-android-engineers">What about Android engineers?</h1>

<p>This approach could be attractive for Android developers unfamiliar with iOS development and who want to expand to iOS. However, it’s not easy to recommend this approach even to Android developers. It would be easier to take the time to learn the basics of iOS development instead of trying to slog through understanding limited and dated Objective-C frameworks and manual memory constructs even with the conveniences of the Kotlin language.</p>

<p>Besides, Swift and Kotlin share a lot from a syntactical perspective, so the most significant hurdle to overcome (as with many languages and frameworks these days) would be learning SwiftUI or UIKit over the language itself.</p>

<p><br /></p>

<h1 id="is-there-a-better-way">Is there a better way?</h1>

<p>You wouldn’t be remiss for thinking this is the only approach to writing platform-dependent code in KMM, given that this is the dominant recommendation from the Kotlin team.</p>

<p>There <em>is</em> a better way: writing your iOS platform-dependent code <strong>directly in Swift.</strong></p>

<p>And that will be the deep dive for the next installment of this series!</p>

<p><br /></p>

<h1 id="is-there-a-time-you-would-recommend-using-expectactual">Is there a time you would recommend using <code class="language-plaintext highlighter-rouge">expect/actual</code>?</h1>

<p>Yes! It makes sense to go down this route if you’re creating a shared Kotlin/Native framework that supports iOS and other platforms.</p>

<p>While my current experience here is limited, I plan to dig into this soon by releasing a shared framework I am building as a part of an app. Given the current landscape of KMM, I’d recommend you consider porting something you’re making to the open-source community to contribute as well!</p>

<p><br /></p>

<h1 id="summary-tradeoffs-of-expectactual">Summary: Tradeoffs of <code class="language-plaintext highlighter-rouge">expect/actual</code>:</h1>

<h3 id="in-favor-of">In favor of:</h3>
<blockquote>
  <p>+ Code is 100% written in Kotlin.
<br />
+ Syntax is fully supported within JetBrains IDEs for compilation and code generation.
<br />
+ Objective-C documentation provides an accurate API reference (over the Swift documentation).
<br />
+ Is useful when building a shared Kotlin/Native framework that targets the iOS platform.</p>
</blockquote>

<h3 id="challenges">Challenges:</h3>
<blockquote>
  <p>- Kotlin/Native iOS APIs support interop with Objective-C APIs, not Swift APIs.
<br />
- As such, Kotlin/Native iOS APIs lack many of the modern conveniences of Swift APIs, and any Swift-exclusive APIs are inaccessible.
<br />
- While accessing Swift APIs not exposed via Kotlin/Native is technically possible, it requires a manual workaround and considerable effort.
<br />
- Working with Objective-C APIs means working with C-APIs, and Kotlin/Native <code class="language-plaintext highlighter-rouge">cinterop</code> interface makes this possible but is complicated due to how the APIs are structured and how you manage memory.</p>
</blockquote>]]></content><author><name>Derek Lee</name></author><category term="Science" /><category term="Kotlin Multiplatform" /></entry><entry><title type="html">The iOS Engineer’s Guide to Beginning Kotlin Multiplatform Development</title><link href="/science/kmm-for-ios-engineers/" rel="alternate" type="text/html" title="The iOS Engineer’s Guide to Beginning Kotlin Multiplatform Development" /><published>2022-08-27T02:00:00+00:00</published><updated>2022-08-27T02:00:00+00:00</updated><id>/science/kmm-for-ios-engineers</id><content type="html" xml:base="/science/kmm-for-ios-engineers/"><![CDATA[<h1 id="tldr">TL;DR</h1>

<ul>
  <li>One of the most essential skills for Kotlin Multiplatform Mobile cross-platform development is sensitivity to what code is platform-dependent or not.</li>
  <li>Platform-dependent code can be written entirely in Kotlin using KMM’s <code class="language-plaintext highlighter-rouge">expect</code> and <code class="language-plaintext highlighter-rouge">actual</code> syntax or by defining an interface in the KMM <code class="language-plaintext highlighter-rouge">common</code> module and implementing it natively in Android (using Kotiln) and iOS (using Swift).</li>
  <li>Platform-independent code is written inside the KMM shared framework and can be used for any business logic for your application that does not directly depend upon any platform-specific code.</li>
  <li>Given the complexities of writing multi-platform code, this post provides an overview, and future posts will dive deeper into these topics.</li>
</ul>

<p><br /></p>

<h1 id="why-multi-platform-development">Why Multi-Platform Development</h1>

<p>After I released <a href="https://apps.apple.com/app/id1443682940">Gap Click on iOS</a>, Android users were not shy about <a href="https://www.youtube.com/watch?v=RCa7lebwhMc">sharing their feedback that they, too, were excited about it</a>. As an iOS engineer with almost no Android experience, I investigated various ways to expand to Android.</p>

<p>With the Kotlin Multiplatform version of GapClick in production for over 18 months and <a href="https://beat-note.app/">having released another app utilizing KMM</a>, I have valuable lessons to share for the technology I’ve chosen.</p>

<p>This post discusses what platform-dependent code is versus platform-independent code and overviews the three primary approaches for sharing code between iOS and Android applications using Kotlin Multiplatform, explicitly targeted at iOS engineers. In subsequent blogs, I’ll dig into the trade-offs with representative code samples and my personal recommendations.</p>

<h2 id="this-post-is-part-of-a-series-on-kotlin-multiplatform"><em>This post is part of a series on Kotlin Multiplatform:</em></h2>
<ol>
  <li><em>The iOS Engineer’s Guide to Beginning Kotlin Multiplatform Development</em></li>
  <li><a href="/science/avoid-this-kmm-technique/" target="_blank"><em>Why iOS Engineers Should Avoid This Glorified KMM Technique</em></a></li>
</ol>

<p><br /></p>

<h1 id="clarifying-kmm-vs-kn">Clarifying KMM vs. K/N</h1>

<p>Before we jump in, let’s make sure we’re on the same page by differentiating between Kotlin Multiplatform and Kotlin Native:</p>

<blockquote>
  <p><strong><a href="https://kotlinlang.org/docs/multiplatform.html">Kotlin Multiplatform</a></strong><br />
<code class="language-plaintext highlighter-rouge">/kɒt lɪn muhl-tee plat-fawrm/</code></p>

  <p>Kotlin Multiplatform Mobile (KMM) is an SDK designed to simplify the development of cross-platform mobile applications. You can share common code between iOS and Android apps and write platform-specific code only where necessary. Common use cases for Kotlin Multiplatform Mobile include implementing a native UI or working with platform-specific APIs.</p>
</blockquote>

<blockquote>
  <p><strong><a href="https://kotlinlang.org/docs/native-overview.html">Kotlin/Native</a></strong><br />
<code class="language-plaintext highlighter-rouge">/kɒt lɪn ney-tiv/</code></p>

  <p>a technology for compiling Kotlin code to native binaries, which can run without a virtual machine.</p>
</blockquote>

<p>I will refer to the technology or SDK of Kotlin Multiplatform (which utilizes Kotlin Native) as <strong>“Kotlin Multiplatform” (or KMM, short for Kotlin Multiplatform Mobile)</strong>. I will use <strong>“native platform”</strong> (the lowercase ‘n’ is on purpose) to refer to actual native implementations on either iOS (Swift) or Android (Kotlin).</p>

<p>(Side note: Although Kotlin/Native also supports other platforms, such as JavaScript, these articles will focus specifically on iOS and Android only.)</p>

<p><br /></p>

<h1 id="step-1-is-your-code-platform-dependent">Step #1: Is Your Code Platform-Dependent?</h1>

<p>The first step in determining where to put your code is to understand if your code is platform-dependent or not. Sometimes this is easy to discern, and other times it can be confusing. Let’s look at some examples to start.</p>

<h2 id="platform-dependent-code">Platform-Dependent Code</h2>

<p>As an iOS engineer, you’ll know your code depends upon a platform framework if you’ve either added it to your project under “Frameworks, Libraries, and Embedded Content”:</p>

<figure class="">
  <img src="/assets/images/kmm/Xcode%20-%20Frameworks%20and%20Libraries.png" alt="Xcode Frameworks, Libraries, and Embedded Content" /><figcaption>
      <em>Xcode Frameworks, Libraries, and Embedded Content.</em>

    </figcaption></figure>

<p>… or you have imported it at the top of a Swift file:</p>

<figure class="">
  <img src="/assets/images/kmm/Xcode%20-%20Import%20Foundation.png" alt="Importing the Foundation framework" /><figcaption>
      <em>Importing the Foundation framework.</em>

    </figcaption></figure>

<p>The most obvious ones might be Foundation or UIKit. Some other obvious ones could be StoreKit, CoreGraphics, AVFoundation, or CoreLocation.</p>

<p>There are also some gray areas you might not realize are platform-dependent, such as networking APIs, accessing the application bundle, or file URLs, to name a few.</p>

<h2 id="platform-independent-code">Platform-Independent Code</h2>

<p>This is any code that you can write without importing any iOS frameworks or libraries. Model objects (or value objects) fall under this category. Of course, your application’s business logic would also be included. I also like to include the code required to implement the mobile architecture approach you’ve chosen, whether it be MVC, MVP, MVVM, or something else. Depending on how sensitive you become to platform dependencies, you’ll find there’s a lot more code that can be shared than you might initially think is possible.</p>

<h2 id="how-code-is-organized-within-a-kmm-project">How Code Is Organized Within a KMM Project</h2>

<p>It might be challenging for those new to KMM to understand how code can be organized inside the project.</p>

<p><em>Platform-dependent</em> code can be located either:</p>
<ol>
  <li>Within the native Android mobile application (written in Kotlin), or within the native iOS mobile application (written in Swift), or</li>
  <li>Within the KMM shared framework written in Kotlin, placed in either:
    <ul>
      <li>“androidMain” for Android-specific implementation code</li>
      <li>“iosMain” for iOS-specific implementation code</li>
    </ul>
  </li>
</ol>

<p><em>Platform-independent</em> code can be placed:</p>
<ul>
  <li>Within the KMM shared framework written in Kotlin, placed in the “common” module</li>
</ul>

<figure class="">
  <img src="/assets/images/kmm/KMM%20Code%20Org%20-%20Overview.jpg" alt="KMM Code Organization" /><figcaption>
      <em>Android and iOS Platforms leveraging a shared framework.</em>

    </figcaption></figure>

<p><br /></p>

<h1 id="step-2-writing-platform-dependent-code">Step #2: Writing Platform-Dependent Code</h1>

<h2 id="option-1-using-kmms-expect-and-actual-syntax">Option #1. Using KMM’s <code class="language-plaintext highlighter-rouge">expect</code> and <code class="language-plaintext highlighter-rouge">actual</code> Syntax</h2>

<p>The Kotlin Multiplatform SDK includes a syntactical construct integrated into Android Studio, which can be used to define classes and functions that are <em>expect</em> -ed (pun intended) to have platform-specific implementations.</p>

<p>This approach is included in the <a href="https://kotlinlang.org/docs/multiplatform-mobile-create-first-app.html">Kotlin Multiplatform for iOS and Android tutorial</a>, and the Kotlin documentation also references this as <a href="https://kotlinlang.org/docs/multiplatform-connect-to-apis.html">the way to access platform-specific APIs</a>. Given this, I assume that this is the recommended approach from the KMM team.</p>

<p>In code: define a class or a function as expected, then provide the actual implementations for each supported platform - all written in Kotlin.</p>

<figure class="">
  <img src="/assets/images/kmm/KMM%20Code%20Org%20-%20expect%20actual.jpg" alt="Code organization using expect/actual" /><figcaption>
      <em>The <code class="language-plaintext highlighter-rouge">common</code> module defines the expected classes and functions, and platform modules define the actual implementation.</em>

    </figcaption></figure>

<h3 id="code-example">Code Example</h3>

<p>Both the <a href="https://kotlinlang.org/docs/multiplatform-mobile-create-first-app.html">Platform class example in the KMM Tutorial</a>, as well as the <a href="https://kotlinlang.org/docs/multiplatform-connect-to-apis.html">UUID function example in the KMM documentation</a>, are straightforward and simple examples of this approach. In the spirit of simple and practical examples, here’s another example of an expected function declaration and the actual implementations for generating the epoch date/time number of seconds since 1970 for UTC:</p>

<p><strong>Common Module <code class="language-plaintext highlighter-rouge">expect</code> declaration:</strong></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">expect</span> <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>androidMain Module <code class="language-plaintext highlighter-rouge">actual</code> implementation:</strong></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="nn">java.time.LocalDateTime</span>
<span class="k">import</span> <span class="nn">java.time.ZoneOffset</span>

<span class="n">actual</span> <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(</span><span class="nc">ZoneOffset</span><span class="p">.</span><span class="nc">UTC</span><span class="p">).</span><span class="nf">toEpochSecond</span><span class="p">(</span><span class="nc">ZoneOffset</span><span class="p">.</span><span class="nc">UTC</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>iosMain Module <code class="language-plaintext highlighter-rouge">actual</code> Implementation:</strong></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="nn">platform.Foundation.*</span>

<span class="n">actual</span> <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nc">NSDate</span><span class="p">.</span><span class="nf">date</span><span class="p">().</span><span class="nf">timeIntervalSince1970</span><span class="p">().</span><span class="nf">toLong</span><span class="p">()</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Suppose you’re not already programming in Swift for iOS. In that case, it might not be apparent that the above <a href="https://stackoverflow.com/a/73295668/1470581">Kotlin source code for the iOS implementation is based on Objective-C APIs</a>, not Swift APIs. (“NSDate” might give this away.) This means that the Kotlin code you’re writing for iOS is effectively “Objective-C-ified Kotlin” and lacks many pleasantries that the Swift language provides. I’ll explain this further when deep-diving into this topic.</p>

<p><br /></p>

<h2 id="option-2-swift-implementation-for-a-common-kotlin-interface">Option #2. Swift Implementation For a “Common” Kotlin Interface</h2>

<p>As an iOS engineer, I quite enjoy writing code in Swift. Therefore, it’s no surprise that I’d prefer to write any iOS platform-specific implementation code directly in that language. This approach allows you to do exactly that! This is the primary benefit for iOS engineers when utilizing this method: writing your code in Swift instead of Objective-C-ified Kotlin.</p>

<p>For the platform-specific Android implementation, the code is still written in Kotlin; the only difference is that the code is placed within the Android app, not the shared framework.</p>

<p>So long as you have defined the interface in the shared framework “common” module, you can implement that interface within your iOS app using Swift (or Objective-C if you like) and within your Android app.</p>

<figure class="">
  <img src="/assets/images/kmm/KMM%20Code%20Org%20-%20common%20interface.jpg" alt="Code organization using a common interface and native implementation." /><figcaption>
      <em>The <code class="language-plaintext highlighter-rouge">common</code> module only defines the interface while the platform-specific implementation is done natively.</em>

    </figcaption></figure>

<h3 id="code-example-1">Code Example</h3>

<p>For simplicity, I’ll continue to utilize the same example of retrieving the current epoch date/time in milliseconds.</p>

<p><strong>Kotlin <code class="language-plaintext highlighter-rouge">common</code> Module Interface:</strong></p>

<p>This is just an interface that we can program to. Nothing fancy here - just the function definition. (iOS friends, you can compare this to a <code class="language-plaintext highlighter-rouge">protocol</code> in Swift.)</p>

<p><em>* Note the package name defined on line #1.</em></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">package</span> <span class="nn">com.company.product.shared.dateprovider.EpochDateProvider</span>

<span class="kd">interface</span> <span class="nc">EpochDateProvider</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Native Android Implementation:</strong></p>

<p>On the Android side, we simply implement this interface. Since we already did something similar above, the implementation here isn’t any different.</p>

<p><em>* Note that the interface is being imported from the shared framework on line #1.</em></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="nn">com.company.product.shared.dateprovider.EpochDateProvider</span>
<span class="k">import</span> <span class="nn">java.time.LocalDateTime</span>
<span class="k">import</span> <span class="nn">java.time.ZoneOffset</span>

<span class="kd">class</span> <span class="nc">AndroidEpochDateProvider</span> <span class="p">:</span> <span class="nc">EpochDateProvider</span> <span class="p">{</span>
    <span class="k">override</span> <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(</span><span class="nc">ZoneOffset</span><span class="p">.</span><span class="nc">UTC</span><span class="p">).</span><span class="nf">toEpochSecond</span><span class="p">(</span><span class="nc">ZoneOffset</span><span class="p">.</span><span class="nc">UTC</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Native iOS Implementation:</strong></p>

<p>On the iOS side, we also simply implement the interface in Swift.</p>

<p>You’ll notice that the function definition in Swift has changed slightly. For example, instead of returning a <code class="language-plaintext highlighter-rouge">Long</code>, the return type is <code class="language-plaintext highlighter-rouge">Int64</code>. <a href="https://kotlinlang.org/docs/native-objc-interop.html">There are several type differences when converting between Swift/Objective-C and Kotlin code</a> that I’ll need to discuss when deep-diving into this technique.</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="kd">import</span> <span class="kt">SharedFramework</span>

<span class="kd">final</span> <span class="kd">class</span> <span class="kt">DarwinEpochDateProvider</span><span class="p">:</span> <span class="kt">EpochDateProvider</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">Int64</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">Int64</span><span class="p">(</span><span class="kt">Date</span><span class="p">()</span><span class="o">.</span><span class="n">timeIntervalSince1970</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Regardless of our platform (Android or iOS), we still get compile-time safety in all of our code because we’re implementing an interface.</p>

<p><br /></p>

<h3 id="what-are-the-differences-between-this-and-using-expectactual">What are the differences between this and using <code class="language-plaintext highlighter-rouge">expect/actual</code>?</h3>

<p>From a code perspective, there isn’t much of a difference. With this technique, the implementation naturally needs to conform to the interface. If you omit the implementation, the compiler will still notify you to implement it, albeit in a different manner than <code class="language-plaintext highlighter-rouge">expect/actual</code>.</p>

<p><em>For example…</em></p>

<p>A repository retrieves flight data for a specific date in your shared framework. To create this repository, you need to pass in an <code class="language-plaintext highlighter-rouge">EpochDateProvider</code> so it knows what the current date and time are:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="nc">NetworkFlightStatusRepository</span><span class="p">(</span>
    <span class="k">private</span> <span class="kd">val</span> <span class="py">dateProvider</span><span class="p">:</span> <span class="nc">EpochDateProvider</span><span class="p">,</span>
    <span class="o">..</span><span class="p">.</span>
<span class="p">)</span> <span class="p">:</span> <span class="nc">FlightStatusRepository</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Therefore, in your Swift code, when you new up an instance of the <code class="language-plaintext highlighter-rouge">NetworkFlightStatusRepository</code> object, an instance of the <code class="language-plaintext highlighter-rouge">EpochDateProvider</code> dependency <em>must</em> be passed in, and the compiler will complain until this is done. <strong>This gives us compile-time safety at the platform level even without <code class="language-plaintext highlighter-rouge">expect/actual</code>:</strong></p>

<figure class="">
  <img src="/assets/images/kmm/FlightStatusRepository.png" alt="Instantiating the FlightStatusRepository" /><figcaption>
      <em>Instantiating the FlightStatusRepository requires an EpochDateProvider to be passed in.</em>

    </figcaption></figure>

<p>Uh oh! This sounds like dependency injection! But… isn’t that hard?</p>

<p>If you’re unaccustomed to it, dependency injection might initially be stifling. Once you get some practice using it (and experience the benefits while testing!), it should become natural to use.</p>

<p>Hopefully, it’s clear from this example that there are ancillary topics, such as dependency injection, that are key to understanding how to make the most of this approach. I know that a proper discussion of this wouldn’t be complete without explaining these other topics, and to keep this post concise, I’ll cover these later in the series.</p>

<p><br /></p>

<h1 id="step-3-writing-platform-independent-code">Step #3: Writing Platform-Independent Code</h1>

<h2 id="kmm-shared-framework-code">KMM Shared Framework Code</h2>

<p>Platform-independent code is written inside the KMM Shared Framework 100% in Kotlin and utilized by Android and iOS applications via the shared framework.</p>

<figure class="">
  <img src="/assets/images/kmm/KMM%20Code%20Org%20-%20All%20Kotlin%20Common.jpg" alt="100% Code in Kotlin Common" /><figcaption>
      <em>All code lives in the shared framework <code class="language-plaintext highlighter-rouge">common</code> module.</em>

    </figcaption></figure>

<h3 id="kotlin-implementation-for-shared-framework-code">Kotlin Implementation For Shared Framework Code</h3>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="nn">com.soywiz.klock.DateTime</span>

<span class="kd">interface</span> <span class="nc">EpochDateProvider</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">DefaultEpochDateProvider</span> <span class="p">:</span> <span class="nc">EpochDateProvider</span> <span class="p">{</span>
    <span class="k">override</span> <span class="k">fun</span> <span class="nf">currentDateTimeInSecondsUTC</span><span class="p">():</span> <span class="nc">Long</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">DateTime</span><span class="p">.</span><span class="nf">nowUnixLong</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Given that this code is written entirely in the shared framework, it can be used by other classes within the shared framework as well as the Android or iOS code.</p>

<p>Those readers with a keen eye likely noticed the <code class="language-plaintext highlighter-rouge">import com.soywiz.klock.DateTime</code> on line #1. Remember how I mentioned that there are some examples of code that appear platform-independent but are actually platform-dependent? Date and times fall under this category. Anyone who has worked with dates and times likely has felt the pain associated with them.</p>

<p>As such, at this time, KMM does not include support for dates and times out of the box, and there are a couple of open-source libraries available for multi-platform development, including <a href="https://docs.korge.org/klock/">Klock</a> and <a href="https://github.com/Kotlin/kotlinx-datetime">kotlinx-datetime</a>.</p>

<hr />

<p>Given these different approaches, you’re probably wondering:</p>

<ul>
  <li>How do I determine what code is platform-dependent or independent?</li>
  <li>What are the trade-offs of each approach?</li>
  <li>When should I use one over the other?</li>
  <li>What are some practical code examples of how to use each one?</li>
</ul>

<p>These will be the main points that I’ll dive into for each one of these approaches next. If you’re considering using KMM in a project and have additional concerns, <a href="/contact/">please let me know</a> so I can include those as well!</p>]]></content><author><name>Derek Lee</name></author><category term="Science" /><category term="Kotlin" /><category term="Kotlin Multiplatform" /><summary type="html"><![CDATA[Techniques for Sharing Code using Kotlin Multiplatform]]></summary></entry><entry><title type="html">PostgreSQL</title><link href="/devrecipes/database/postgresql/" rel="alternate" type="text/html" title="PostgreSQL" /><published>2022-03-01T00:00:00+00:00</published><updated>2022-03-01T00:00:00+00:00</updated><id>/devrecipes/database/PostgreSQL</id><content type="html" xml:base="/devrecipes/database/postgresql/"><![CDATA[<h2 id="installation--setup">Installation / Setup</h2>

<h4 id="install-via-brew">Install via Brew</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>brew <span class="nb">install </span>postgresql
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="start-postgres-service-via-brewx">Start Postgres Service (via Brew)x</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>brew services start postgresql
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="creating--dropping-databases">Creating / Dropping Databases</h2>

<h4 id="create-a-new-database">Create a new database</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>createdb &lt;db_name&gt;      <span class="c"># Creates a new database with the given name</span>
<span class="nv">$ </span>createdb <span class="sb">`</span><span class="nb">whoami</span><span class="sb">`</span>       <span class="c"># Creates a new database for the current logged in user, and allow connection via psql</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="drop-database">Drop Database</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>dropdb <span class="nt">--help</span>               <span class="c"># Drop database</span>
<span class="nv">$ </span>dropdb <span class="nt">-i</span> &lt;database_name&gt;   <span class="c"># With confirmation</span>
<span class="nv">$ </span>dropdb &lt;database_name&gt;      <span class="c"># Without confirmation</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="psql">PSQL</h2>

<h4 id="help">Help</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>psql <span class="nt">--help</span>             <span class="c"># Command line options</span>
<span class="nv">$ </span>psql <span class="nt">--help</span><span class="o">=</span>commands    <span class="c"># Backslash commands</span>
<span class="nv">$ </span>psql <span class="nt">--help</span><span class="o">=</span>variables   <span class="c"># Special variables</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="connect-to-a-specific-database">Connect to a specific database</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>psql <span class="nt">-d</span> &lt;db_name&gt;
<span class="nv">$ </span>psql &lt;db_name&gt;          <span class="c"># No need to use -d option</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="list-available-databases">List available databases</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>psql <span class="nt">-l</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="export-db-schema">Export DB Schema</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>pg_dump <span class="nt">--help</span>
<span class="nv">$ </span>pg_dump <span class="nt">-s</span> &lt;database_name&gt; <span class="o">&gt;</span> filename    <span class="c"># To file</span>
<span class="nv">$ </span>pg_dump <span class="nt">-s</span> &lt;database_name&gt; | pbcopy      <span class="c"># To clipboard</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="output-postgresql-history-shows-all-previously-run-sql-commands">Output PostgreSQL History (Shows all previously run SQL commands)</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">cat</span> ~/.psql_history
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="load-a-sql-file-into-a-db">Load a SQL File into a DB</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>psql <span class="nt">-d</span> &lt;database_name&gt; <span class="nt">-f</span> &lt;path_and_filename&gt;
<span class="nv">$ </span>psql <span class="nt">-h</span> &lt;host&gt; <span class="nt">-p</span> &lt;port&gt; <span class="nt">-u</span> &lt;database&gt;

<span class="c"># Example (will prompt for password)</span>
<span class="nv">$ </span>psql <span class="nt">-h</span> somehost-012345.db.elephantsql.com <span class="nt">-p</span> 5432 <span class="nt">-d</span> mydatabase <span class="nt">-U</span> username <span class="nt">-f</span> ./sql/initial_schema.ddl
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="psql-console-commands">psql Console Commands</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="se">\h</span>                     <span class="c"># Show help (does not show backslash commands)</span>
<span class="se">\h</span> CREATE              <span class="c"># Show help for the CREATE command</span>

<span class="se">\l</span>                     <span class="c"># Show all databases</span>

<span class="se">\c</span> &lt;database_name&gt;     <span class="c"># Connect to database</span>

<span class="se">\d</span>                     <span class="c"># Show tables/views/sequences</span>
<span class="se">\d</span>t                    <span class="c"># Show all tables</span>
<span class="se">\d</span> &lt;tablename&gt;         <span class="c"># Describe table</span>

<span class="se">\i</span> &lt;filename&gt;          <span class="c"># Load SQL file</span>

<span class="se">\q</span>                     <span class="c"># Quit</span>

show config_file<span class="p">;</span>      <span class="c"># Output the location of the postgresql.conf file</span>
show <span class="nb">time </span>zone<span class="p">;</span>        <span class="c"># Output Time Zone (current session only)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="postgresql-time-zone-setting">Postgresql Time Zone Setting</h2>

<p>Defaults to the system time zone at the time of install if not specified.</p>

<p>Location of postgresql.conf file: <code class="language-plaintext highlighter-rouge">/usr/local/var/postgres/postgresql.conf</code><br />
Timezone setting: <code class="language-plaintext highlighter-rouge">timezone = "UTC"</code></p>

<h2 id="sample-sql-statements">Sample SQL Statements</h2>

<h4 id="create-database">Create Database</h4>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">create</span> <span class="k">database</span> <span class="n">studioreservations_dev</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Create User + Grant Access</strong></p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">create</span> <span class="k">user</span> <span class="k">admin</span> <span class="k">with</span> <span class="k">encrypted</span> <span class="n">password</span> <span class="s1">'my-secret-password'</span><span class="p">;</span>

<span class="k">grant</span> <span class="k">all</span> <span class="k">privileges</span> <span class="k">on</span> <span class="k">database</span> <span class="o">&lt;</span><span class="n">database_name</span><span class="o">&gt;</span> <span class="k">to</span> <span class="k">admin</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="create-table-using-various-data-types">Create Table Using various data types</h4>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">users</span> <span class="p">(</span>
  <span class="n">id</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
  <span class="n">email</span> <span class="nb">character</span> <span class="nb">varying</span><span class="p">,</span>
  <span class="n">password_digest</span> <span class="nb">character</span> <span class="nb">varying</span><span class="p">,</span>
  <span class="n">created_at</span> <span class="nb">timestamp</span> <span class="k">without</span> <span class="nb">time</span> <span class="k">zone</span> <span class="k">default</span> <span class="k">current_timestamp</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
  <span class="n">updated_at</span> <span class="nb">timestamp</span> <span class="k">without</span> <span class="nb">time</span> <span class="k">zone</span> <span class="k">default</span> <span class="k">current_timestamp</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
  <span class="n">name</span> <span class="nb">character</span> <span class="nb">varying</span>
<span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="insert-data-into-table">Insert data into table</h4>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">insert</span> <span class="k">into</span> <span class="n">users</span> <span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span> <span class="k">values</span> <span class="p">(</span><span class="s1">'name@domain.com'</span><span class="p">,</span> <span class="s1">'my-secret-Password-123'</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="delete-all-rows-from-table">Delete all rows from table</h4>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">truncate</span> <span class="k">table</span> <span class="o">&lt;</span><span class="n">tablename</span><span class="o">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="drop-database-1">Drop Database</h4>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">drop</span> <span class="k">database</span> <span class="o">&lt;</span><span class="n">database_name</span><span class="o">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="rename-table">Rename Table</h4>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">alter</span> <span class="k">table</span> <span class="o">&lt;</span><span class="n">current_table_name</span><span class="o">&gt;</span> <span class="k">rename</span> <span class="k">to</span> <span class="o">&lt;</span><span class="n">new_table_name</span><span class="o">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="notes-on-sql-queries">Notes on SQL Queries</h4>

<ul>
  <li><strong><em>Need to use single quotes</em></strong> when inserting data via the console.</li>
  <li>Matching on wildcard characters:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">_</code> matches on a single character (as compared to <code class="language-plaintext highlighter-rouge">?</code> in Oracle SQL)</li>
      <li><code class="language-plaintext highlighter-rouge">%</code> matches on any number of characters (as compared to <code class="language-plaintext highlighter-rouge">*</code> in Oracle SQL)</li>
    </ul>
  </li>
</ul>

<h2 id="configuration">Configuration</h2>

<p>Default Postgres configuration file location: <code class="language-plaintext highlighter-rouge">/usr/local/var/postgres/postgresql.conf</code></p>

<p>Useful settings:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">max_connections = 100</code> <em>(requires restart)</em></li>
</ul>

<h2 id="troubleshooting">Troubleshooting</h2>

<h3 id="server-was-running-but-client-could-not-connect">Server was running but client could not connect</h3>

<p>Error Message:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="s2">"psql: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "</span>/var/run/postgresql/.s.PGSQL.5432<span class="s2">"?"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Solved by: Removing postmaster.pid file: <code class="language-plaintext highlighter-rouge">rm /usr/local/var/postgres/postmaster.pid</code></p>

<p>Reference: <a href="http://stackoverflow.com/questions/13573204/psql-could-not-connect-to-server-no-such-file-or-directory-mac-os-x">Stackoverflow post</a></p>

<h2 id="error-psql-error-could-not-connect-to-server-no-such-file-or-directory">Error: psql: error: could not connect to server: No such file or directory</h2>

<p>Try to start the server manually: <code class="language-plaintext highlighter-rouge">$ pg_ctl -D /usr/local/var/postgres/ start</code></p>

<p>A different error explains what is wrong:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>waiting <span class="k">for </span>server to start....2021-05-04 09:24:12.203 JST <span class="o">[</span>56328] FATAL: database files are incompatible with server

2021-05-04 09:24:12.203 JST <span class="o">[</span>56328] DETAIL: The data directory was initialized by PostgreSQL version 11, which is not compatible with this version 13.2.

stopped waiting
pg_ctl: could not start server
Examine the log output.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Resolution:</p>
<ul>
  <li>Upgrade the database using brew: <code class="language-plaintext highlighter-rouge">$ brew postgresql-upgrade-database</code></li>
  <li>Can now connect to the DB via psql</li>
</ul>

<h2 id="research-topics">Research Topics</h2>

<ul>
  <li>Differences between Postgresql and MySql as it relates to TIMESTAMP fields</li>
  <li>The Postgresql “JSON” column type</li>
</ul>

<h2 id="references">References</h2>

<ul>
  <li><a href="http://www.thegeekstuff.com/2009/04/15-practical-postgresql-database-adminstration-commands/">http://www.thegeekstuff.com/2009/04/15-practical-postgresql-database-adminstration-commands/</a></li>
</ul>]]></content><author><name>Derek Lee</name></author><category term="Dev Recipes" /><category term="Database" /><summary type="html"><![CDATA[Installation / Setup]]></summary></entry><entry><title type="html">README as Code</title><link href="/science/readme-as-code/" rel="alternate" type="text/html" title="README as Code" /><published>2022-02-19T05:00:00+00:00</published><updated>2022-02-19T05:00:00+00:00</updated><id>/science/readme-as-code</id><content type="html" xml:base="/science/readme-as-code/"><![CDATA[<p>I make a point of always running the test suite (at least the fastest of the bunch: the unit tests) from the command line before pushing code to CI to confirm that all has gone smoothly.</p>

<p>Why is this important to do?</p>

<p>One of my changes could have impacted another part of the codebase, or merging someone else’s changes might have affected mine.</p>

<p>Additionally, since the CI machine runs the tests from the command line and not through the IDE, running the tests in the same manner locally is expected to produce the same results.</p>

<p>I recently helped kick off a new iOS project and taught the engineers how to run the tests from the command line.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>xcodebuild <span class="nt">-project</span> MyProject.xcodeproj <span class="nt">-scheme</span> MyProject <span class="nt">-destination</span> <span class="s2">"platform=iOS Simulator,OS=latest,name=iPhone 13"</span> clean build <span class="nb">test</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Their initial response?</p>

<blockquote>
  <p>“Do we have to type this <strong>every</strong> time?”</p>
</blockquote>

<p>Compare this to running tests for a JavaScript application:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>npm run <span class="nb">test</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or even a simple Gradle (Java or Kotlin) test suite:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>./gradlew clean build <span class="nb">test</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>While these two examples are arguably more straightforward to execute, each build chain requires different commands.</p>

<p>Remembering all of these commands is like memorizing trivial facts. Of course, there’s no harm in doing it, and it could come in handy someday, but aren’t there more complicated problems that deserve our focus and brainpower?</p>

<h2 id="natural-tendencies">Natural Tendencies</h2>

<p>Thankfully, one is naturally inclined to make such a complicated task simpler to perform. For example, single-stack software engineers focusing solely on mobile development might suggest a tool like <a href="https://fastlane.tools/">Fastlane</a>. While Fastlane is a great tool, it is specific to iOS and Android development. Other developers might recommend using a shell script which, while extremely powerful, can become more challenging to organize once you have more than a few.</p>

<h2 id="an-unlikely-candidate">An Unlikely Candidate</h2>

<p>The idea of using a Makefile was introduced to me without much explanation by a long-time Pivot<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> when I first joined Pivotal Labs for precisely these kinds of tasks. Since that time, I’ve come to understand the benefits of leveraging Makefiles are much more than just saving a few keystrokes, and I recommend utilizing them on all projects now.</p>

<h2 id="getting-started">Getting Started</h2>

<p>Intended as a build tool for C programs, <a href="https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_1.html">Make’s documentation states</a>:</p>

<blockquote>
  <p>“You can use <code class="language-plaintext highlighter-rouge">make</code> with any programming language whose compiler can be run with a shell command.”</p>
</blockquote>

<p>Let’s take a look at a sample <code class="language-plaintext highlighter-rouge">Makefile</code> for an iOS application that contains a couple Make “targets”:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>tests:
	xcodebuild <span class="se">\</span>
		<span class="nt">-project</span> <span class="s2">"MyProject.xcodeproj"</span> <span class="se">\</span>
		<span class="nt">-scheme</span> <span class="s2">"MyProject"</span> <span class="se">\</span>
		<span class="nt">-destination</span> <span class="s2">"platform=iOS Simulator,OS=latest,name=iPhone 13"</span> <span class="se">\</span>
		clean build <span class="nb">test

</span>beta:
	./bin/testflight-deploy.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<p>A “target” is the name of an action to carry out. There are two “targets” here: <code class="language-plaintext highlighter-rouge">tests</code> and <code class="language-plaintext highlighter-rouge">beta</code>.</p>

<h3 id="tests"><code class="language-plaintext highlighter-rouge">tests:</code></h3>

<p>This Make target leverages the <code class="language-plaintext highlighter-rouge">xcodebuild</code> command-line tool to execute the test suite associated with the provided Xcode project and scheme on an iPhone 13 Simulator device running the latest version of iOS.</p>

<p>This Make target can be run simply by typing:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>make tests
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="beta"><code class="language-plaintext highlighter-rouge">beta:</code></h3>

<p>The steps needed to deploy a beta version of the application are more complicated than a single line. Therefore, this Make target executes a shell script in the <code class="language-plaintext highlighter-rouge">bin</code> folder to deploy the application to <a href="https://developer.apple.com/testflight/">TestFlight</a> and can be run simply by typing:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>make beta
</pre></td></tr></tbody></table></code></pre></div></div>

<p><br /></p>

<h2 id="the-hidden-power-of-makefiles">The Hidden Power of Makefiles</h2>

<p>Great! So we’ve saved a few keystrokes by doing this. But is that all we’ve accomplished? Hardly!</p>

<h3 id="simplicity">Simplicity</h3>

<p>In addition to saving some keystrokes, this dramatically simplifies executing complex commands. Now you only need to remember a short word or phrase instead of the entire command to run these tasks!</p>

<h3 id="discoverability">Discoverability</h3>

<p>How do I build the code? How do I run the tests? How do I deploy the code?</p>

<p>Placing your most important and frequently used commands into a Makefile makes them immediately discoverable by other members of your team. Now it can all be collected into a single location, ready to be discovered by anyone, anytime!</p>

<p>I like to define discoverability as:</p>

<blockquote>
  <p>How easy or difficult it is for someone to discover and understand for themselves <em>any aspect of your software project</em>.</p>
</blockquote>

<p><a href="http://cleancoder.com">Uncle Bob</a> calls this <a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882">Clean Code</a> as it directly relates to code, and in the case of consuming an API, many may refer to the “developer experience.” However, I like to apply this concept to all aspects of software using the term “Discoverability.”</p>

<h3 id="learning--executable-documentation">Learning + Executable Documentation</h3>

<p>What if this developer is entirely new to the tech stack you are using?</p>

<p>Referencing a Makefile, the developer not only knows what tasks are possible to run but can also understand the commands executed to perform that task. In addition, they can see how to perform these tasks and independently learn by reading the Makefile or referenced scripts.</p>

<h3 id="consistency-within-projects">Consistency Within Projects</h3>

<p>Your source code repository <a href="https://github.com/derekleerock/ToDoList">may contain multiple applications</a> such as a back-end and multiple front-ends (web, iOS, Android, etc.). Given each one has a Makefile, the tasks can be consistent across all platforms.</p>

<p>Need to run the tests on the iOS app?</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">cd </span>ios <span class="o">&amp;&amp;</span> make tests
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Need to run the tests for the back-end?</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">cd </span>server <span class="o">&amp;&amp;</span> make tests
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Need to run the tests for the web app?</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">cd </span>web <span class="o">&amp;&amp;</span> make tests
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="consistency-across-organizations">Consistency Across Organizations</h3>

<p>Are you transferring to a new project within your department?</p>

<p>Applying Makefiles across an entire organization or company further increases their benefits. No need to stress as you will already know how to find and execute the most common tasks!</p>

<h3 id="automation">Automation</h3>

<p>Last and not least is automation. At the risk of belaboring an already well-supported argument, I will keep this brief:</p>

<ul>
  <li>Automation ensures consistent execution each time</li>
  <li>Automating laborious tasks removes the possibility of human error</li>
  <li>Automation removes process deviation as a possible cause of bugs</li>
</ul>

<p><br /></p>

<h2 id="common-questions-and-concerns">Common Questions and Concerns</h2>

<blockquote>
  <p>“What do I need to know to get started using a Makefile?”</p>
</blockquote>

<p>There are only two things you need to know to get started using a Makefile:</p>

<h3 id="1-indent-execution-lines-using-tabs-not-spaces">#1. Indent execution lines using tabs (<em>not</em> spaces)</h3>

<p>The majority of modern IDEs understand this and will take care of it for you.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>beta:
	./bin/testflight-deploy.sh
^^^^^^^^
   ↑↑ Caution! This needs to be a single tab, not multiple spaces.
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="2-use-phony-for-targets-that-match-directories-in-the-execution-location">#2. Use <code class="language-plaintext highlighter-rouge">.PHONY:</code> for targets that match directories in the execution location</h3>

<p>Your <code class="language-plaintext highlighter-rouge">Makefile</code> exists with a target named <code class="language-plaintext highlighter-rouge">test:</code> in a location where a directory called <code class="language-plaintext highlighter-rouge">test</code> also exists:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>

drwxr-xr-x@ username 704 Dec 14 18:02 <span class="nb">.</span>
drwxr-xr-x@ username 256 Dec 14 18:02 ..
<span class="nt">-rw-r--r--</span>@ username 425 Apr 30  2021 Makefile
drwxr-xr-x@ username  96 Dec 14 18:04 <span class="nb">test</span>

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

<p>Therefore, in your <code class="language-plaintext highlighter-rouge">Makefile</code>, you need to indicate that the <code class="language-plaintext highlighter-rouge">test</code> directory <em>is not something that the Makefile should be concerned with</em> by marking it as <code class="language-plaintext highlighter-rouge">.PHONY</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>.PHONY: <span class="nb">test

test</span>:
	npm run <span class="nb">test</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>IMPORTANT:</strong> Don’t forget the period “.” before <code class="language-plaintext highlighter-rouge">PHONY</code> and also ensure PHONY is written in all caps, otherwise this won’t work.</p>

<p><br /></p>

<blockquote>
  <p>“Can I call one make task from another?”</p>
</blockquote>

<p>Absolutely! Define your new target the same way and denote which other targets it should invoke.</p>

<p>In this following example, the <code class="language-plaintext highlighter-rouge">tests</code> target sorts the Xcode project file first before executing the unit tests:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="nb">sort</span>:
	@perl ./bin/sortXcodeProject <span class="s2">"MyProject.xcodeproj/project.pbxproj"</span>

unit-tests:
	@/usr/bin/time xcodebuild <span class="se">\</span>
		<span class="nt">-project</span> <span class="s2">"MyProject.xcodeproj"</span> <span class="se">\</span>
		<span class="nt">-scheme</span> <span class="s2">"MyProject"</span> <span class="se">\</span>
		<span class="nt">-destination</span> <span class="s2">"platform=iOS Simulator,OS=latest,name=iPhone 13"</span> <span class="se">\</span>
		clean build <span class="nb">test

</span>tests: <span class="nb">sort </span>unit-tests
</pre></td></tr></tbody></table></code></pre></div></div>

<p><br /></p>

<blockquote>
  <p>“What if the script I want to execute is long?”</p>
</blockquote>

<p>Using a backslash (“\”) character, you can break long commands across multiple lines. This limits the length of a line so the reader can easily consume the entire command without scrolling horizontally and improves the readability of the command by placing each option on a new line:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>tests:
	xcodebuild <span class="se">\</span>
		<span class="nt">-project</span> <span class="s2">"MyProject.xcodeproj"</span> <span class="se">\</span>
		<span class="nt">-scheme</span> <span class="s2">"MyProject"</span> <span class="se">\</span>
		<span class="nt">-destination</span> <span class="s2">"platform=iOS Simulator,OS=latest,name=iPhone 13"</span> <span class="se">\</span>
		clean build <span class="nb">test</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>For multi-line or complex commands, simplify a Make target by extracting its contents into a separate shell script and calling that from the Makefile:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>beta:
	./bin/testflight-deploy.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I follow a rule of thumb similar to what <a href="http://cleancoder.com">Uncle Bob</a> proposes for the maximum number of arguments to a function: if a command is three lines or less, then chances are it’s OK to place directly inside the Makefile. Anything longer should be extracted to a separate script and placed in a <code class="language-plaintext highlighter-rouge">/bin</code> directory.</p>

<p><br /></p>

<blockquote>
  <p>“How can I show or hide the command executed in the output?”</p>
</blockquote>

<p>When executing a Makefile, they naturally output the commands for each task.</p>

<p>If you would like to hide these commands from the output, add a “@” character to the beginning of the command:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>beta:
	@./bin/testflight-deploy.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<p><br /></p>

<blockquote>
  <p>“Why use Make when there are other tools available?”</p>
</blockquote>

<p>I consider the primary benefits of leveraging Make to be significant:</p>

<ul>
  <li>Make comes installed with Unix-based operating systems by default.</li>
  <li>Make target execution is consistent across operating systems.</li>
  <li>Anyone who is already comfortable executing basic shell commands on a Linux-based OS can easily use Make.</li>
  <li>Make doesn’t require any additional dependencies or knowledge of a specific language.</li>
  <li>Make it super simple to use.</li>
</ul>

<p><br /></p>

<blockquote>
  <p>“What alternatives to Make could be considered?”</p>
</blockquote>

<p>A quick internet search will result in a long list of alternatives to using a Makefile.</p>

<p>However, I would consider that any alternative would likely:</p>
<ul>
  <li>Require you to install a new tool.</li>
  <li>Require you to learn the custom format or structure that the tool utilizes.</li>
  <li>Create a dependency upon that tool.</li>
  <li>Require you to update that tool as it is maintained.</li>
</ul>

<p><br /></p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>How ‘discoverable’ are the most common tasks a team member performs on your project? For example, if someone new were to join the team tomorrow, how much hand-holding would be necessary for them to get started? Conversely, how easy would it be for them to get started without any assistance from anyone else?</p>

<p>Leveraging Makefiles <strong>in your applications</strong> provides:</p>

<ul>
  <li>A simple and repeatable way to automate complex tasks.</li>
  <li>A menu of tasks allowing team members to discover what is possible quickly.</li>
  <li>Documentation of these processes for team members to learn from.</li>
  <li>Task consistency across all platforms for a single application.</li>
</ul>

<p>Leveraging Makefiles <strong>across your organization</strong> provides:</p>

<ul>
  <li>Consistency across projects.</li>
  <li>A simple way for new members to come up to speed when joining a new project.</li>
</ul>

<p>Introduce a Makefile to your project and take a step closer to “README as code”!</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>A “Pivot” is someone who works at Pivotal. We’re still using this word today because “VMware-ers” doesn’t have the same ring to it. <a href="https://fortune.com/2022/02/16/mark-zuckerberg-calls-meta-employees-metamates/#:~:text=In%20the%20latest%20step%20in,now%20be%20called%20%E2%80%9CMetamates.%E2%80%9D">VMware-mates, anyone?</a> Bueller? <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Derek Lee</name></author><category term="Science" /><category term="Communication" /><category term="Simplicity" /><category term="Discoverability" /><category term="Automation" /><summary type="html"><![CDATA[I make a point of always running the test suite (at least the fastest of the bunch: the unit tests) from the command line before pushing code to CI to confirm that all has gone smoothly.]]></summary></entry><entry><title type="html">Efficiently Learning IDE Keyboard Shortcuts</title><link href="/art/how-to-learn-keyboard-shortcuts/" rel="alternate" type="text/html" title="Efficiently Learning IDE Keyboard Shortcuts" /><published>2022-01-29T03:00:00+00:00</published><updated>2022-01-29T03:00:00+00:00</updated><id>/art/how-to-learn-keyboard-shortcuts</id><content type="html" xml:base="/art/how-to-learn-keyboard-shortcuts/"><![CDATA[<p>There are few low-investment, yet incredibly high-gain, productivity hacks to supercharge your developer skills, such as learning a few keyboard shortcuts. If you’re like me, you might’ve thought that starting with your favorite IDE’s typical keyboard shortcut reference documentation might be an excellent place to start… that is, until you open it up and feel your head start to spin:</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/JetBrains%20IntelliJ%20Keyboard%20Shortcuts%20macOS.png" alt="IntelliJ macOS Keyboard Shortcuts PDF" /><figcaption>
      <em>This may be a good choice of reading if you’re having difficulty sleeping at night.</em>

    </figcaption></figure>

<p>Thankfully, there are only a couple of challenges you’ll need to overcome to learn keyboard shortcuts more effectively.</p>

<h2 id="challenge-1-there-are-so-many-where-to-start-️">Challenge #1: There are so many!! Where to start? 🤷🏽‍♂️</h2>

<h3 id="pair-programming">Pair programming</h3>

<p>Arguably, one of the easiest ways to learn keyboard shortcuts (among other things!) is through pair programming.</p>

<p>Regardless of experience level, chances are both engineers already know a few shortcuts. For example, if you’re pairing, and your pair uses a shortcut you don’t know, you could  stop and ask: “How did you do that?” If you don’t want to interrupt the “flow” of your pairing session, jot a note down on a sticky and ask during your next break.</p>

<p>Or better yet, make it easier for you to discern what keyboard shortcuts are being used by installing a plugin such as <a href="https://plugins.jetbrains.com/plugin/7345-presentation-assistant">Presentation Assistant</a> (for JetBrains IDEs), which displays the keyboard shortcuts along the bottom of the screen as you type them.</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/IntelliJ%20Presentation%20Assistant.gif" alt="IntelliJ Presentation Assistant Demo" /><figcaption>
      <em>IntelliJ Presentation Assistant Plugin in action!</em>

    </figcaption></figure>

<p>Another tool to consider for macOS is <a href="https://keylimepie.app/">KeyLimePie</a> which displays keyboard shortcuts typed with any IDE or application.</p>

<h3 id="soloing">Soloing</h3>

<p>If you don’t have a pair to learn from, then you might need to do a little digging to find a good place to start. If you know what you want to do but don’t know how to do it, there are a few ways to discover these.</p>

<p><em>(I’m using a JetBrains IDE for these examples, however many of these tips apply across IDEs.)</em></p>

<h4 id="have-the-ide-teach-you">Have the IDE teach you</h4>

<p>There’s nothing like getting reprimanded when not doing something correctly to help you learn! 😅 Yet another excellent example of feedback!</p>

<p>Plugins like <a href="https://plugins.jetbrains.com/plugin/9792-key-promoter-x">Key Promoter X</a> will let you know each time you use the mouse for an action that has a corresponding keyboard shortcut.</p>

<p>And as if scolding you each time wasn’t enough, it keeps track of how many times you’ve made a mistake, so that you can feel even <em>more</em> guilty.</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/IntelliJ%20Key%20Promoter%20X%20Demo.gif" alt="IntelliJ Key Promoter X Demo" /><figcaption>
      <em>IntelliJ Key Promoter X Plugin in action!</em>

    </figcaption></figure>

<h4 id="dig-through-menus">Dig through menus</h4>

<p>Have an idea of what you want to do but aren’t sure what the shortcut is? With most IDEs, there are a few ways you can go digging for this information, the first of which is the menus.</p>

<p>JetBrians’ menus, in particular, are intuitively organized. Whether it’s navigation, code, refactoring, or any other topic, a simple peek at the menu shows the commands with their respective keyboard shortcut right next to them.</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/IntelliJ%20Code%20Menu.png" alt="IntelliJ Code Menu" /><figcaption>
      <em>IntelliJ ‘Code’ menu options, showing commands with the respective keyboard shortcut to the right</em>

    </figcaption></figure>

<h4 id="search-all">Search all</h4>

<p>Another approach specific to JetBrains is their handy “search all” feature. Double-tap the shift key in any Jetbrains IDE to show a list of everything the IDE has. Options here include commands with keyboard shortcuts, IDE settings, and all sorts of other goodies.</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/IntelliJ%20Search%20All.png" alt="IntelliJ Search All" /><figcaption>
      <em>IntelliJ ‘Search All’ menu, showing commands with the respective keyboard shortcut right next to it</em>

    </figcaption></figure>

<h4 id="keymap-settings">Keymap settings</h4>

<p>Accessing the preferences (<code class="language-plaintext highlighter-rouge">⌘ + ,</code>) and selecting <code class="language-plaintext highlighter-rouge">Keymap</code> displays the complete list. Conveniently, you can search by title or by keystroke as well. IntelliJ will also warn you of duplicate mappings.</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/IntelliJ%20Keymap%20Settings.png" alt="IntelliJ Keymap Settings" /><figcaption>
      <em>IntelliJ Keymap Settings</em>

    </figcaption></figure>

<h2 id="challenge-2-remembering-them">Challenge #2: Remembering them</h2>

<h3 id="step-1-put-it-in-view">Step #1: Put it in view</h3>

<p>When I first joined Pivotal Labs (now <a href="https://tanzu.vmware.com/labs">Tanzu Labs</a>), the idea of using sticky notes to the extent that they do just wasn’t natural to me (<a href="https://www.intercom.com/blog/podcasts/miros-andrey-khusid-on-the-art-of-distributed-teamwork/">nowadays it seems their reputation proceeds them 😂</a>). However, I saw these experienced practitioners using sticky notes for <em>everything</em> and found this very inspiring! So much so that I ended up ditching my Moleskin for a sharpie and stack of stickies.</p>

<p>Therefore, when I struggled to remember keyboard shortcuts, I started to write them down on a sticky note and stick it on my monitor.</p>

<p>Anytime I forget, it just takes a glance down to jog my mind.</p>

<figure class="">
  <img src="/assets/images/learning-keyboard-shortcuts/Sticky%20Note%20On%20Monitor.jpg" alt="Sticky note on monitor for 'Reveal In Finder'" /><figcaption>
      <em>This one took me quite some time to discover!</em>

    </figcaption></figure>

<h3 id="step-2-make-a-point-to-practice">Step #2: Make a point to practice</h3>

<p>When learning a new command or keyboard shortcut, I’ll go out of my way to try it a few times to get the feel of it. You could compare this to increasing your vocabulary when studying a new language: the more times you recall it with high accuracy, the longer you can go without quizzing yourself. When learning a new shortcut for the first time, practice it a few times. Increase your awareness and be deliberate to try out your new skill. After several days, it should start to sink in.</p>

<h3 id="step-3-removing-the-guard-rails">Step #3: Removing the guard rails</h3>

<p>Toss the sticky note into the trash before you feel comfortable with your new skill. Or better yet, replace it with a new one.</p>

<p>If you find yourself struggling to remember several shortcuts, make a cheat sheet and put them all on a single sticky note.</p>

<p>If you added a sticky note to your monitor for even just one new keyboard shortcut each day, you’d be surprised at how quickly these add up!</p>

<h2 id="bonus-task-switching">BONUS: Task Switching</h2>

<p>Having been initially most comfortable with Xcode, I was admittedly hesitant about learning a new IDE, afraid that my brain would not be able to tell them apart. However, after learning how to navigate IntelliJ on macOS effectively, I gained additional confidence.</p>

<p>However, at one point, I found myself assisting with a workshop held outside my company’s office in an external classroom equipped with only Windows machines. Using IntelliJ, my fingers instinctively tried the familiar macOS keyboard shortcuts. Simply switching the command key to the control key got me part of the way there, but alas, many of them were different.</p>

<p>Whether switching IDEs or OSs, using the “sticky note” method mentioned above, I was surprised at how quickly my brain and fingers could adapt.</p>

<p>I like to compare this to renting a car. When you first sit in a rental car, most aspects of your environment are familiar. However, there might be some notable differences. For example, whether the vehicle is an automatic or manual transmission or if you are traveling outside your native country, you may find yourself driving while sitting on the car’s left-hand side or the right-hand side. While at first uncomfortable, once you’ve acquired the skill, these cues are enough to switch your brain to the right setting for the action you’re about to take. Likewise, task-switching from one OS to another or one IDE to another provides a similar cue to help you switch to the proper keyboard shortcut settings in your mind.</p>

<p>Practice most certainly helps, too!</p>

<h2 id="further-personalization">Further Personalization</h2>

<p>Sometimes there aren’t keyboard shortcuts for aspects of the IDE that I want further control over. But, particularly for JetBrains, I have a few favorites that I find to be productivity boosters that I always tend to use.</p>

<p>If you’re pair programming, talk this through with your pair to ensure that you don’t have any keyboard shortcut conflicts between the two of you. Ideally, try to find an agreement on a keymap within the team of engineers who are pairing, and maybe take advantage of JetBrain’s feature for sharing these settings across machines.</p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>It won’t take long until you feel increased productivity after learning even just a few keyboard shortcuts. You can make this process more effective by:</p>

<ul>
  <li>Learning new shortcuts through pair programming or installing a plugin to remind you when you miss one</li>
  <li>Writing new keyboard shortcuts down on sticky notes and putting them into easy view</li>
  <li>Practicing these shortcuts and refreshing your sticky notes regularly</li>
</ul>

<p>Do you have any other helpful tips for learning keyboard shortcuts? <a href="https://twitter.com/derekleerock">Let me know!</a></p>]]></content><author><name>Derek Lee</name></author><category term="Art" /><category term="IDE" /><category term="Keyboard Shortcuts" /><category term="Productivity" /><summary type="html"><![CDATA[Super charge your development productivity!]]></summary></entry><entry><title type="html">Git Bisect</title><link href="/devrecipes/git/bisect/" rel="alternate" type="text/html" title="Git Bisect" /><published>2020-01-01T00:00:00+00:00</published><updated>2020-01-01T00:00:00+00:00</updated><id>/devrecipes/git/bisect</id><content type="html" xml:base="/devrecipes/git/bisect/"><![CDATA[<p><a href="http://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git#Binary-Search">Reference Documentation</a></p>

<p>Git Bisect is a super helpful tool to determine where a bug or issue was introduced into the codebase when you’re not sure what commit caused it.</p>

<h1 id="finding-the-commit-that-introduced-a-bug">Finding the Commit that Introduced a Bug</h1>

<h4 id="step-1-tell-git-to-start-the-bisect-process">Step #1: Tell Git to start the bisect process</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>git bisect start
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="step-2-tell-git-that-the-current-commit-is-where-the-problem-exists">Step #2: Tell Git that the current commit is where the problem exists</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>git bisect bad
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="step-3-tell-git-which-commit-you-know-things-were-working-properly">Step #3: Tell Git which commit you know things were working properly</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>git bisect good &lt;commit <span class="nb">hash </span>or tag&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next, Git will check out a commit somewhere approximately in the middle.</p>

<p>You test to see if the issue still exists in that commit or not.</p>

<h4 id="step-4-then-you-just-need-to-tell-git-the-result-of-your-test">Step #4: Then, you just need to tell Git the result of your test</h4>

<p>If the issue still exists, tell Git the commit is <strong>bad</strong>:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>git bisect bad
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If the issue isn’t there, tell Git the commit is <strong>good</strong>:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>git bisect good
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Git will split the remaining commits in half and check out a commit somewhere in the middle of this set.</p>

<p>Return to Step #4 and repeat until Git has found the commit that introduced the issue.</p>

<hr />

<h1 id="once-youve-found-the-commit-that-introduced-the-issue">Once You’ve Found the Commit that Introduced the Issue</h1>

<p>Once you have the commit that caused the unexpected behavior, tell Git you’re done with the bisect process:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>git bisect reset
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Voila! You now know which commit introduced the issue. Now for the fun part: fixing it!</p>

<hr />

<h1 id="what-does-the-output-look-like">What does the output look like?</h1>

<p>Let’s check out a sample output from a real-world example:</p>

<h4 id="starting-the-bisect-process">Starting the bisect process</h4>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="o">[</span>project-directory <span class="o">(</span>Current Branch: main<span class="o">)]</span><span class="nv">$ </span>git bisect start
<span class="o">[</span>project-directory <span class="o">(</span>Current Branch: main<span class="o">)]</span><span class="nv">$ </span>git bisect bad
<span class="o">[</span>project-directory <span class="o">(</span>Current Branch: main<span class="o">)]</span><span class="nv">$ </span>git bisect good ef6c9010
Bisecting: 61 revisions left to <span class="nb">test </span>after this <span class="o">(</span>roughly 6 steps<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="finding-the-commit-that-introduced-the-issue">Finding the commit that introduced the issue</h4>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect bad
Bisecting: 30 revisions left to <span class="nb">test </span>after this <span class="o">(</span>roughly 5 steps<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;

<span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect bad
Bisecting: 14 revisions left to <span class="nb">test </span>after this <span class="o">(</span>roughly 4 steps<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;

<span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect bad
Bisecting: 7 revisions left to <span class="nb">test </span>after this <span class="o">(</span>roughly 3 steps<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;

<span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect good
Bisecting: 3 revisions left to <span class="nb">test </span>after this <span class="o">(</span>roughly 2 steps<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;

<span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect good
Bisecting: 1 revision left to <span class="nb">test </span>after this <span class="o">(</span>roughly 1 step<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;

<span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect good
Bisecting: 0 revisions left to <span class="nb">test </span>after this <span class="o">(</span>roughly 0 steps<span class="o">)</span>

&lt;Git displays information about the commit it checked out <span class="k">for </span>testing&gt;

<span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect good
&lt;commit <span class="nb">hash</span><span class="o">&gt;</span> is the first bad commit

_&lt;Git displays information about the commit&gt;_

x files changed, y insertions<span class="o">(</span>+<span class="o">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="wrapping-up-the-bisect-process">Wrapping up the bisect process</h4>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="o">[</span>project-directory <span class="o">((</span>no branch, bisect started on main<span class="o">))]</span><span class="nv">$ </span>git bisect reset

Previous HEAD position was &lt;Commit Hash and Message&gt;
Switched to branch <span class="s1">'main'</span>
Your branch is up to <span class="nb">date </span>with <span class="s1">'origin/main'</span><span class="nb">.</span>

<span class="o">[</span>project-directory <span class="o">(</span>Current Branch: main<span class="o">)]</span> <span class="err">$</span>
</pre></td></tr></tbody></table></code></pre></div></div>]]></content><author><name>Derek Lee</name></author><category term="Dev Recipes" /><category term="Git" /><category term="Git" /><summary type="html"><![CDATA[Reference Documentation]]></summary></entry></feed>