<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Show me da code</title>
    <description>Talk is so easy</description>
    <link>http://sortega.github.io/</link>
    <atom:link href="http://sortega.github.io/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Homerow Mods in OS X</title>
        <description>
&lt;p&gt;Since I got the Advantage 360 keyboard I’ve been experimenting with keyboard
customizations, and I’ve found homerow mods to be a very comfortable way to
use shortcuts at scale without having to move your hands from the home row. The
idea is use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asdf&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jkl;&lt;/code&gt; keys as modifiers when pressed in combination 
with other keys but as regular keys when pressed alone (&lt;a href=&quot;precondition_homerow_mods&quot;&gt;longer explanation
here&lt;/a&gt;). Once you get used to it, you feel you have 
one hand tied to your back when you use a regular keyboard.&lt;/p&gt;

&lt;p&gt;Unfortunately, I cannot customize the integrated keyboard of my MacBook laptop
using &lt;a href=&quot;zmk&quot;&gt;ZMK&lt;/a&gt; or &lt;a href=&quot;qmk&quot;&gt;QMK&lt;/a&gt;, so I had to find another way. I found
&lt;a href=&quot;https://github.com/kmonad/kmonad&quot;&gt;KMonad&lt;/a&gt;, a program that intercepts your keyboard taps and modifies
them according to a configuration file written in pseudo-lisp.&lt;/p&gt;

&lt;h2 id=&quot;setup-procedure&quot;&gt;Setup procedure&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;Install Stack. Stack is a (the?) Haskell build tool. KMonad is written in 
Haskell as you can guess from such a name. You can install it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew 
install haskell-stack&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;KMonad piggybacks on the kernel extension that 
&lt;a href=&quot;https://karabiner-elements.pqrs.org/&quot;&gt;Karabiner-Elements&lt;/a&gt; uses to intercept keyboard events. Install
the &lt;a href=&quot;https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/releases/download/v2.1.0/Karabiner-DriverKit-VirtualHIDDevice-2.1.0.pkg&quot;&gt;Karabiner driver&lt;/a&gt; or the full thing.&lt;/li&gt;
  &lt;li&gt;Activate the driver:
    &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Clone the KMonad repo and build it:
    &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone &lt;span class=&quot;nt&quot;&gt;--recursive&lt;/span&gt; https://github.com/vosaica/kmonad.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;kmonad
git checkout Upgrade-DriverKit-VirtualHIDDevice
git submodule update &lt;span class=&quot;nt&quot;&gt;--init&lt;/span&gt;
stack build &lt;span class=&quot;nt&quot;&gt;--flag&lt;/span&gt; kmonad:dext &lt;span class=&quot;nt&quot;&gt;--extra-include-dirs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;c_src/mac/Karabiner-DriverKit-VirtualHIDDevice/include/pqrs/karabiner/driverkit:c_src/mac/Karabiner-DriverKit-VirtualHIDDevice/src/Client/vendor/include
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Create a configuration file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.kmonad.kbd&lt;/code&gt;. You can start from mine and
modify it to your liking after taking a look at the 
&lt;a href=&quot;https://github.com/kmonad/kmonad/blob/master/keymap/tutorial.kbd&quot;&gt;KMonad tutorial&lt;/a&gt;. I’m using Command-Alt-Shift-Ctrl as my
mapping for the left hand (and reversed for the right one) but other people
use different combinations. See the &lt;a href=&quot;https://precondition.github.io/home-row-mods#what-are-home-row-mods&quot;&gt;Precondition post&lt;/a&gt;
for more details.
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(defcfg
    ;; Limit KMonad to the integrated keybboard, use (iokit-name) to apply to all
    input  (iokit-name &quot;Apple Internal Keyboard / Trackpad&quot;)
    output (kext)
       
    ;; Comment this if you want unhandled events not to be emitted
    fallthrough true
       
    ;; Set this to false to disable any command-execution in KMonad
    allow-cmd true
)
   
;; lmet -&amp;gt; cmd
;; lalt -&amp;gt; option
;; fn   -&amp;gt; fn

(defsrc
    esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12
    grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc
    tab  q    w    e    r    t    y    u    i    o    p    [    ]    \
    caps a    s    d    f    g    h    j    k    l    ;    '    ret
    lsft z    x    c    v    b    n    m    ,    .    /    rsft up
    fn   lctl lalt lmet           spc            rmet ralt left down rght
)
   
(defalias
    met_a (tap-hold-next-release 200 a lmet)
    alt_s (tap-hold-next-release 200 s lalt)
    sft_d (tap-hold-next-release 200 d lsft)
    ctl_f (tap-hold-next-release 200 f lctl)
   
    ctl_j (tap-hold-next-release 200 j rctl)
    sft_k (tap-hold-next-release 200 k rsft)
    alt_l (tap-hold-next-release 200 l lalt)
    met_; (tap-hold-next-release 200 ; rmet)
   
    ;; let's use caps as control unless double-tapped
    ccaps (multi-tap 300 lctl caps)
   
    fn (around (layer-toggle function) fn)
)
   
(deflayer default
  _       f1      f2      f3      f4      f5      f6      f7      f8      f9      f10     f11     f12
  _       _       _       _       _       _       _       _       _       _       _       _       _    _
  _       _       _       _       _       _       _       _       _       _       _       _       _    _
  @ccaps  @met_a  @alt_s  @sft_d  @ctl_f  _       _       @ctl_j  @sft_k  @alt_l  @met_;  _       _
  _       _       _       _       _       _       _       _       _       _       _       _       _
  @fn     _       _       _                       _                       _       _       _       _    _
)
   
;; We need to explicitly map the function keys to their original function because
;; KMonad precludes the default configuration. As a bonus, enable vim-like cursor when pressing fn.
(deflayer function
  _       brdn    brup    lp      mctl    bldn    blup    prev    pp      next    mute    vold    volu
  _       _       _       _       _       _       _       _       _       _       _       _       _    _
  _       _       _       _       _       _       _       _       _       _       _       _       _    _
  _       _       _       _       _       _       left    down    up      right   _       _       _
  _       _       _       _       _       _       _       _       _       _       _       _       _
  _       _       _       _                       _                       _       _       _       _    _
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Go to Settings &amp;gt; Privacy &amp;amp; Security &amp;gt; Input Monitoring and add 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/bin/launchctl&lt;/code&gt; and the kmonad binary.&lt;/li&gt;
  &lt;li&gt;Test the configuration:
    &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;kmonad ~/.kmonad.kbd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;If everything works as expected, you can install KMonad as a service by creating
a launch config at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Library/LaunchDaemons/local.kmonad.plist&lt;/code&gt; (adjust paths if
you installed kmonad elsewhere):
    &lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;plist&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;local.kmonad&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Program&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/your_username/.local/bin/kmonad&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/your_username/.local/bin/kmonad&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/your_username/.kmonad.kbd&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;true&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardOutPath&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/tmp/kmonad.stdout&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardErrorPath&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/tmp/kmonad.stderr&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Restart or start/stop the daemon manually with these commands:
    &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;launchctl load &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; /Library/LaunchDaemons/local.kmonad.plist
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;launchctl unload /Library/LaunchDaemons/local.kmonad.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;If you get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;§&lt;/code&gt; rather than backtick it might help getting a custom input
source. Use
&lt;a href=&quot;/assets/homerow-mods/US%20ISO%20HiTilde.keylayout.zip&quot;&gt;this one&lt;/a&gt;
(&lt;a href=&quot;https://discussions.apple.com/thread/253602833?answerId=256749398022&quot;&gt;source&lt;/a&gt;) by copying it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Library/Keyboard Layouts&lt;/code&gt; and
selecting it in System Preferences &amp;gt; Keyboard &amp;gt; Input Sources.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://precondition.github.io/home-row-mods&quot;&gt;Precondition post on homerow mods&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kmonad/kmonad/blob/master/keymap/tutorial.kbd&quot;&gt;KMonad tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/amiorin/4c74f63fe599a1dcbd0933628df1aac9&quot;&gt;Example homerow mods config and tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nimishgautam.github.io/posts/kmonad-osx/&quot;&gt;Post&lt;/a&gt; on how to run KMonad as a service&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sun, 03 Dec 2023 12:00:00 +0000</pubDate>
        <link>http://sortega.github.io/tools/2023/12/03/homerow-mods/</link>
        <guid isPermaLink="true">http://sortega.github.io/tools/2023/12/03/homerow-mods/</guid>
      </item>
    
      <item>
        <title>A bicycle for your memory</title>
        <description>
&lt;p&gt;Computers have the need to store huge amounts of information and, at the same time, being able to access that memory 
at blazingly fast rates. This poses the problem of how to get a fast and large memory when hardware memories are either fast, like registers or L1 cache lines; or big, like hard drives or solid state drives.&lt;/p&gt;

&lt;table style=&quot;width: 75%; margin: 1em auto; font-size: 80%&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;Memory&lt;/th&gt;
            &lt;th&gt;Size&lt;/th&gt;
            &lt;th&gt;Speed&lt;/th&gt;
            &lt;th&gt;Comment&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;CPU register&lt;/td&gt;
            &lt;td&gt;A few bytes&lt;/td&gt;
            &lt;td&gt;One CPU cycle (200-300 picoseconds)&lt;/td&gt;
            &lt;td&gt;A register holds the data the CPU can operate on&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;RAM memory&lt;/td&gt;
            &lt;td&gt;A few gigabytes&lt;/td&gt;
            &lt;td&gt;100 nanoseconds&lt;/td&gt;
            &lt;td&gt;Applications need their data to be here to be responsive&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Hard drive&lt;/td&gt;
            &lt;td&gt;Many gigabytes&lt;/td&gt;
            &lt;td&gt;150 microseconds&lt;/td&gt;
            &lt;td&gt;All your applications and data being kept locally have a copy here&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Internet&lt;/td&gt;
            &lt;td&gt;Infinite (for all purposes)&lt;/td&gt;
            &lt;td&gt;10-40 milliseconds&lt;/td&gt;
            &lt;td&gt;Technically &lt;i&gt;other people's hard drives&lt;/i&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;This is solved in computer architecture by the interplay of two ideas: a &lt;strong&gt;memory hierarchy&lt;/strong&gt; and &lt;strong&gt;virtual memory&lt;/strong&gt;.
The &lt;a href=&quot;https://en.wikipedia.org/wiki/Memory_hierarchy&quot;&gt;memory hierarchy&lt;/a&gt; consists of a pyramid with the fastest and smallest memories on the tip and slower 
but bigger ones at the base. This arrangement allows you to have a complete copy of the information at the base, which is the biggest. Then, you can keep copies of the actively used information closer to the pyramid apex for better performance. &lt;a href=&quot;https://en.wikipedia.org/wiki/Virtual_memory&quot;&gt;Virtual memory&lt;/a&gt; is the illusion of having a single memory space which is the result of the collaboration of specific hardware (MMU, CPU features) with the operative system to transparently move data across the levels of the pyramid. The result is that, for most purposes and most of the time, programs running in your computer get to use a single memory space that feels as big as the base of the pyramid and almost as fast as its top.&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/cyborg/memory_hierarchy.png&quot; alt=&quot;Memory hierarchy with 4 levels: CPU registers, CPU cache, RAM memory and hard drive&quot; style=&quot;width: 75%&quot; /&gt;
    &lt;p style=&quot;text-align: center; font-size: 90%&quot;&gt;
    Simplified memory hierarchy
    &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Apart from computers, humans are rich information processors&lt;sup id=&quot;fnref:human_comp&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:human_comp&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and memory plays a paramount role in what 
it means to be a human. On one hand it is an important element of personal identity. Imagine a movie villain using 
technology or black magic&lt;sup id=&quot;fnref:magic&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:magic&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; to swap the memories of two twin brothers. In some philosophical sense we are what we remember, and we will have a hard time deciding who is who in this contrived situation.&lt;/p&gt;

&lt;p&gt;On the other hand, memories are needed for our minds to work because without them, we will have only the raw input of our senses and no other concept or idea to work with. The extent to which we can understand the world, communicate with others and act depends on using those mental building blocks or &lt;a href=&quot;https://en.wikipedia.org/wiki/Chunking_(psychology)&quot;&gt;chunks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another aspect of being human not so directly related to information processing is tool making and tool use. Thanks 
to these, we have come a long way since we harnessed the power of fire and stone. Steve Jobs eloquently explained in 
&lt;a href=&quot;https://youtu.be/ob_GX50Za6c&quot;&gt;this talk&lt;/a&gt; how humans will lose in almost all categories&lt;sup id=&quot;fnref:best&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:best&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; of an Olympic Games in which other animals 
were allowed to take part. We are not the fastest, we cannot travel the furthest, nor in the most efficient way. 
However, any cyclist is more efficient in energy per distance than a Condor, the most efficient animal. Then, he 
declared computers to be like &lt;em&gt;a bicycle for the mind&lt;/em&gt;. Back then, personal computing was being rolled out, and we 
were oblivious to the directions these new machines would cybernetically extend us.&lt;/p&gt;

&lt;h2 id=&quot;the-cyborg-memory-hierarchy&quot;&gt;The Cyborg Memory Hierarchy&lt;/h2&gt;

&lt;p&gt;At this point we have all the ingredients to define what I call the &lt;strong&gt;cyborg memory hierarchy&lt;/strong&gt;: extending human capabilities with technology (cyborg) so we can enhance in-brain memory and extend it with external information (memory hierarchy).&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/cyborg/cyborg_memory_hierarchy.png&quot; alt=&quot;Cyborg memory hierarchy with the levels described in the main text&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;p style=&quot;text-align: center; font-size: 90%&quot;&gt;
    Cyborg memory hierarchy
    &lt;/p&gt;
&lt;/div&gt;

&lt;h3 id=&quot;level-0-working-memory&quot;&gt;Level 0. Working memory&lt;/h3&gt;

&lt;p&gt;Our working memory is composed of a phonological loop, where you can keep repeating a phone number while you search 
for pen and paper; the visuo-spatial sketchpad, where you can mentally manipulate shapes; and some very 
limited number of slots that can hold ideas, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Chunking_(psychology)&quot;&gt;chunks&lt;/a&gt;, for manipulation. Early George A. Miller work 
estimated that the typical mind was able to hold 5 ± 2 chunks&lt;sup id=&quot;fnref:magic_number&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:magic_number&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, but more recent work suggests we 
are limited to about 4 chunks.&lt;/p&gt;

&lt;p&gt;I doubt we will cybernetically extend our working memory until brain-computer interfaces become a reality, but I 
have some good news in the methodology front. The reason Miller got initially confused with the amount of mental 
slots is that we can do more with less by having more elaborate and high level chunks. For example, I might be able 
to work in my mind with only three digits (e.g. 7, 1, 4) but if they are dates, then I can hold many more digits 
(e.g. 1492, 2001, 1991).&lt;/p&gt;

&lt;p&gt;In fact, you can see expertise in any field as the slow and effortful learning of ever higher-level chunks and 
mental models (read &lt;a href=&quot;https://www.goodreads.com/book/show/26312997-peak&quot;&gt;Peak&lt;/a&gt; by Anders Ericsson). My advice: hunt all the important concepts in your 
field of interest and commit them to long-term memory (see next section).&lt;/p&gt;

&lt;h3 id=&quot;level-1-long-term-memory&quot;&gt;Level 1. Long-term memory&lt;/h3&gt;

&lt;p&gt;These are memories that we can use fluently, regardless of our smartphone batteries being dead. These are critical for anything we do with fluency like speaking a language, being expert at anything, or being creative, which implies &lt;a href=&quot;http://www.pearlleff.com/in-praise-of-memorization&quot;&gt;recombination of ideas that should be at the same time in our minds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some of these memories are &lt;em&gt;declarative&lt;/em&gt; and can be expressed as answers to explicit questions. “What’s the capital of Georgia? &lt;a href=&quot;https://en.wikipedia.org/wiki/Tbilisi&quot;&gt;Tbilisi&lt;/a&gt; or Atlanta”. We can extend our declarative memories by reading and studying for which there is a wealth of technologies and channels but the main enemy to beat is how fast those new memories fade away from us.&lt;/p&gt;

&lt;p&gt;We know thanks to Hermann Ebbinghaus and his tedious self-experimentation with memorizing long sequences of nonsense 
words that facts decay exponentially in our minds unless reviewed and inter-related to other memories. His work was published in the XIX century, but no specific software was created to optimize when to review which piece of knowledge until Piotr Wozniak wrote the &lt;a href=&quot;https://super-memory.com/english/history.htm&quot;&gt;first spaced repetition software (SRS)&lt;/a&gt; in 1987. The underlying idea of this kind of software is that you encode what you have already understood and learned and want to keep in you memory as flash cards (short questions and answers) and the system keeps track of when to do reviews. Due to Ebbinghaus forgetting curve, the interval between reviews grows exponentially, so you see the typical card again after months or years. This means that you can keep many tens of thousands of cards in your level-zero memory at the cost of a few minutes of daily review.&lt;/p&gt;

&lt;p&gt;For a nice explanation of how to implement this with &lt;a href=&quot;https://apps.ankiweb.net/&quot;&gt;Anki&lt;/a&gt;, one of the most popular SRS nowadays, I recommend reading &lt;a href=&quot;http://augmentingcognition.com/ltm.html&quot;&gt;Augmenting Long-term Memory&lt;/a&gt; by Michael Nielsen. He is also experimenting with articles that embed an SRS like &lt;a href=&quot;https://quantum.country&quot;&gt;this one&lt;/a&gt; about quantum computing.&lt;/p&gt;

&lt;p&gt;If you want to read more about good practices with SRS, Wozniak’s &lt;a href=&quot;https://www.supermemo.com/en/archives1990-2015/articles/20rules&quot;&gt;Twenty Rules of Formulating Knowledge&lt;/a&gt; is the most authoritative source and Soren Bjornstad’s &lt;a href=&quot;https://controlaltbackspace.org/memory/designing-precise-cards/&quot;&gt;Rules for Designing Precise Anki Cards&lt;/a&gt; is a great complement.&lt;/p&gt;

&lt;p&gt;Paraphrasing Nielsen, &lt;em&gt;SRS makes declarative memory a choice&lt;/em&gt;. If we ever think that keeping a fact or a concept available in our mind is more valuable than 5 minutes of our time&lt;sup id=&quot;fnref:gwern&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:gwern&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; we can do it&lt;sup id=&quot;fnref:uni&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:uni&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;What about non-declarative memory? Muscle memory cannot be reduced to declarative facts, no one is able to learn how to bike by reading &lt;em&gt;How to ride a bike&lt;/em&gt;. However, some creative thinking can help us to bridge the gap in some cases. For example, I use Anki to learn application shortcuts declaratively and then, as opportunity to use them in the day to day happens I build the muscle memory.&lt;/p&gt;

&lt;h3 id=&quot;level-2-personal-notes-and-annotations&quot;&gt;Level 2. Personal notes and annotations&lt;/h3&gt;

&lt;p&gt;When we process information we tend to take notes or perform annotations in the medium itself, so we can come back to them without needing long-term memorization. Note that technically, pen and notebook are already cybernetic extensions for this purpose.&lt;/p&gt;

&lt;p&gt;These notes are indeed very useful for us to solidify our understanding and organization of ideas, specially if we do a write-up like a blog post. The mere act of writing, even at book marginalia, also improves our initial memorization.&lt;/p&gt;

&lt;p&gt;However, the value of these notes is limited unless they are connected and easily searchable. To get that extra value we need to up both our methodological and technological games.&lt;/p&gt;

&lt;p&gt;The quintessential technology to fill this gap is the personal wiki in which you can seamlessly write notes, keep 
them inter-linked and securely access this second brain from all your devices. There is an inexhaustible offer of wikis out there (&lt;a href=&quot;https://www.wikimatrix.org/&quot;&gt;open source&lt;/a&gt; and &lt;a href=&quot;https://alternativeto.net/software/notion/?feature=wiki&amp;amp;platform=software-as-a-service&quot;&gt;SaaS&lt;/a&gt;). My recommendation is to pick one and try to use it unless blocked by a showstopper. A very common failure mode is to keep tuning your wiki configuration without really using it.&lt;/p&gt;

&lt;p&gt;I personally use &lt;a href=&quot;https://tiddlywiki.com/&quot;&gt;TiddlyWiki&lt;/a&gt;&lt;sup id=&quot;fnref:tw&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:tw&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; with the amazing Soren’s &lt;a href=&quot;https://sobjornstad.github.io/TiddlyRemember/&quot;&gt;TiddlyRemember plugin&lt;/a&gt; to define SRS cards directly from within my wiki notes. When reviewing them in Anki I get a valuable link to their original context.&lt;/p&gt;

&lt;p&gt;On the methodology front, I recommend the philosophy of &lt;a href=&quot;https://writingcooperative.com/zettelkasten-how-one-german-scholar-was-so-freakishly-productive-997e4e0ca125&quot;&gt;Zettelkasten&lt;/a&gt; that was introduced by Niklas 
Luhmann, a very prolific German social scientist that implemented the logical equivalent to a wiki for his research 
notes using Victorian technology.  Luhmann was carefully digesting other academics books and articles into chunks or 
ideas written in index cards that were linked, tagged and annotated to form a web of knowledge that he traversed in a 
myriad ways, leading to serendipitous connections bringing a deeper understanding—and many publications! By the way, 
&lt;em&gt;zettel&lt;/em&gt; is German for note while &lt;em&gt;kasten&lt;/em&gt; means box.&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/cyborg/zettlekasten.png&quot; alt=&quot;Drawing of furniture to hold index cards in small drawers&quot; style=&quot;width: 80%&quot; /&gt;
    &lt;p style=&quot;text-align: center; font-size: 90%&quot;&gt;
    How a personal wiki looks like in steampunk style
    &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Soren Bjornstad adapted TiddlyWiki for Zettelkasten and he extensively explains the result in &lt;a href=&quot;https://www.youtube.com/watch?v=GjpjE5pMZMI&quot;&gt;this video&lt;/a&gt;. The template is &lt;a href=&quot;https://sobjornstad.github.io/tzk/&quot;&gt;available&lt;/a&gt; for anyone to use.&lt;/p&gt;

&lt;h3 id=&quot;level-3-selected-sources-and-everything-else&quot;&gt;Level 3. Selected sources and everything else&lt;/h3&gt;

&lt;p&gt;At this level, we have all the source material—books&lt;sup id=&quot;fnref:plato&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:plato&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;, articles—we collected and totally or partially read and quite likely you took notes and made flashcards about. At the mid-level of technology, you can picture cozy bookshelves at home but to give you more value, you need to get it organized and searchable.&lt;/p&gt;

&lt;p&gt;For this purpose I use &lt;a href=&quot;https://calibre-ebook.com/&quot;&gt;Calibre&lt;/a&gt;, which was presented to me as &lt;em&gt;the iTunes of ebooks&lt;/em&gt;. Any other ebook organizer will do as long as you have a nice desktop search engine, so you can easily get back to the tidbits of your books that are neither in you head nor your notes. The spotlight search of Mac OS X is a good starting point for this.&lt;/p&gt;

&lt;p&gt;Apart from these selected sources, we have ad-hoc information needs which we satisfy by using general search engines.
Google, Bing, DuckDuckGo… choose your poison but once chosen, learn to use it properly
(&lt;a href=&quot;https://www.lifehack.org/articles/technology/20-tips-use-google-search-efficiently.html&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://www.gwern.net/Search&quot;&gt;2&lt;/a&gt;).&lt;/p&gt;

&lt;h3 id=&quot;does-it-make-sense-a-partial-implementation-of-this-cyborg-memory-hierarchy&quot;&gt;Does it make sense a partial implementation of this Cyborg Memory Hierarchy?&lt;/h3&gt;

&lt;p&gt;I think that any missing piece is problematic.&lt;/p&gt;

&lt;p&gt;If you have SRS without a personal wiki you will tend to either create flashcards for things that are not really meant for that, and you might burn out; or otherwise, you might let go many valuable things.&lt;/p&gt;

&lt;p&gt;If you have a wiki without SRS you won’t be fluid enough to take advantage of many things. For example, you can have great coding design patterns documented in your notes and never remember to apply them when the right conditions apply.&lt;/p&gt;

&lt;p&gt;If you only have a search engine, you might not even know what to search about to solve a problem and your thinking will tend to be more shallow (related book: &lt;a href=&quot;https://www.goodreads.com/book/show/9778945-the-shallows&quot;&gt;The Shallows: What the Internet is Doing to Out Brains&lt;/a&gt;).&lt;/p&gt;

&lt;h3 id=&quot;how-neuralink-or-some-other-technology-will-change-this&quot;&gt;How Neuralink or some other technology will change this?&lt;/h3&gt;

&lt;p&gt;I have no idea. I can only speculate that tighter integration with our brains can collapse some levels or open new 
ones that we do not even understand today. Maybe the Neuralink-enabled Anki feels exactly like Neo’s learning Kung 
Fu in The Matrix.&lt;/p&gt;

&lt;h3 id=&quot;your-personal-cyborg-memory-hierarchy&quot;&gt;Your personal cyborg memory hierarchy&lt;/h3&gt;

&lt;p&gt;If you have some concept or implementation similar to the cyborg memory hierarchy or this post has inspired you to 
implement one for yourself I am very interested in knowing about your experiences. Please write a comment about it!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:human_comp&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a false dichotomy as &lt;em&gt;computer&lt;/em&gt; was a job title for humans! Until the invention of the modern electronic computer, a &lt;em&gt;computer&lt;/em&gt; was a person—most likely a woman—skilled enough at mathematical computation to, for example, slowly tabulate a logarithm table. &lt;a href=&quot;#fnref:human_comp&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:magic&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;“Any sufficiently advanced technology is indistinguishable from magic” (Arthur C. Clarke) &lt;a href=&quot;#fnref:magic&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:best&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;One exception is that we can keep walking and running sustainably way longer than other animals. When we were hunter-gatherers &lt;a href=&quot;https://en.wikipedia.org/wiki/Persistence_hunting&quot;&gt;persistence hunting&lt;/a&gt;—hunting by exhausting your prey—was a thing. Another exception is our eye-to-hand coordination for throwing rocks and spears. I suppose people less apt at these things were wiped out from the gene pool by Mother Evolution. &lt;a href=&quot;#fnref:best&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:magic_number&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This is the origin of the &lt;em&gt;magic number 7&lt;/em&gt; (5 + 2) that is used to prescribe no more than 7 levels or class inheritance, no more than 7 attributes per class, no more than… &lt;a href=&quot;#fnref:magic_number&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:gwern&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Gwern estimates in &lt;a href=&quot;https://www.gwern.net/Spaced-repetition#how-much-to-add&quot;&gt;about 2 minutes&lt;/a&gt; the total time that it takes remember a fact &lt;em&gt;foreverish&lt;/em&gt; with Anki. I am doubling that estimate to compensate form the rest of us not being as bright as him. &lt;a href=&quot;#fnref:gwern&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:uni&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;What a great pity not having had SRS in my tool belt during my university years. I would now remember more of the original content, and I would not have needed re-learning it years after my graduation. &lt;a href=&quot;#fnref:uni&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:tw&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;One of the strong points of TiddlyWiki is how you can deeply customize it for your purposes without leaving its markup language and dropping to JavaScript. Its plugin mechanism is also based in the same customizations that a regular user can afford and that means the small community around it has published a huge amount of plugins that you can mix and match. &lt;a href=&quot;#fnref:tw&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:plato&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;A bookshelf was considered disruptive technology in times of Plato and Plato considered &lt;a href=&quot;https://fs.blog/an-old-argument-against-writing/&quot;&gt;books will make people forgetful&lt;/a&gt;. We can forgive him because there was no SRS back them to compensate for this effect. &lt;a href=&quot;#fnref:plato&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 27 Mar 2022 12:00:00 +0000</pubDate>
        <link>http://sortega.github.io/other/2022/03/27/cyborg-memory-hierarchy/</link>
        <guid isPermaLink="true">http://sortega.github.io/other/2022/03/27/cyborg-memory-hierarchy/</guid>
      </item>
    
      <item>
        <title>How to waste less time and space with Terraform</title>
        <description>&lt;p&gt;I’ve been using &lt;a href=&quot;https://www.terraform.io/&quot;&gt;Terraform&lt;/a&gt; quite extensively at work for some time and,
over time, I’ve been interacting with more and more modules. At the same time,
I need to work with a rather small HDD for modern standards where every GB
counts.&lt;/p&gt;

&lt;p&gt;Terraform’s default configuration wastes a lot of space by keeping a separate
copy of the provider binary in each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.terraform/plugins&lt;/code&gt;. In my case that was
about 20 GB.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; .terraform &lt;span class=&quot;nt&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt;/plugins &lt;span class=&quot;se&quot;&gt;\;&lt;/span&gt; | xargs &lt;span class=&quot;nb&quot;&gt;du&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-hs&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--total&lt;/span&gt;
19G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, you can configure Terraform CLI to use a centalized cache directory as
long as your OS supports hardlinks. To do so, create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.terraformrc&lt;/code&gt; with
contents &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugin_cache_dir = &quot;$HOME/Library/Caches/terraform/plugin-cache&quot;&lt;/code&gt; or
some other directory that makes more sense to you. &lt;a href=&quot;https://www.terraform.io/docs/configuration-0-11/providers.html#provider-plugin-cache&quot;&gt;Read more&lt;/a&gt; about 
this configuration.&lt;/p&gt;

&lt;p&gt;After that, you can take advantage of the consolidated cache.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ~/Library/Caches/terraform/plugin-cache
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; .terraform &lt;span class=&quot;nt&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt;/plugins &lt;span class=&quot;se&quot;&gt;\;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;...some terraform inits...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;du&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-hs&lt;/span&gt; ~/Library/Caches/terraform/plugin-cache
819M
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On top of saved space you will have faster &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform init&lt;/code&gt;s.&lt;/p&gt;

</description>
        <pubDate>Mon, 24 May 2021 11:46:00 +0000</pubDate>
        <link>http://sortega.github.io/tools/2021/05/24/terraform-plugin-cache/</link>
        <guid isPermaLink="true">http://sortega.github.io/tools/2021/05/24/terraform-plugin-cache/</guid>
      </item>
    
      <item>
        <title>Let DNS do what DNS does</title>
        <description>
&lt;p style=&quot;font-size: 80%; color: #333&quot;&gt;
&lt;b&gt;tl;dr&lt;/b&gt;: fight entropy in your Kafka Connect connector configurations by resolving cluster nodes with my &lt;a href=&quot;https://github.com/sortega/connect-dns-provider&quot;&gt;connect-dns-provider&lt;/a&gt; plugin
&lt;/p&gt;

&lt;p&gt;Thermodynamics presents us with the ruthless teaching that &lt;em&gt;global&lt;/em&gt; entropy
or disorder is constantly growing and that &lt;em&gt;locally&lt;/em&gt; you can
only fence it off by expending energy.&lt;/p&gt;

&lt;p&gt;For living beings, this means the need to ingest enough food over time to
sustain themselves.  For the world of software development, this means the
will to refactor and to introduce new organizing principles over time.
The alternative to paying this price is a deteriorating codebase and
supporting artefacts that exposes you to risks and reduces the development
pace over time. Eventually, you reach the point in which you add one bug
per bug removed and you can declare the thermal dead of the system.&lt;/p&gt;

&lt;p&gt;How do you keep that entropy at bay? Ruthlessly remove what is no longer needed
and introduce structure to support what is actually needed.  Bonus points
if you avoid falling for the shiny object syndrome and choose the appropriate
proven technology even if it’s not the latest hype.&lt;/p&gt;

&lt;p&gt;A personal recent example of this for me is related to working with a 
&lt;a href=&quot;https://kafka.apache.org/&quot;&gt;Kafka&lt;/a&gt; ecosystem in which we use &lt;a href=&quot;https://docs.confluent.io/platform/current/connect/index.html&quot;&gt;Connect&lt;/a&gt; connectors
to move events in and out of a main Kafka cluster.  Connectors are created,
modified and removed by means of some scripts your can launch as Jenkins
pipelines.&lt;/p&gt;

&lt;p&gt;A pain point of this setup is that the configuration for some connectors
require of a list of servers and ports of other clusters. For example, if you
are using the Cassandra source connector, you are expected to configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect.cassandra.contact.points=server1:port1,server2:port2&lt;/code&gt;.  When you
rotate or redimension those nodes, you need to update the scripts and run
the pipelines anew.&lt;/p&gt;

&lt;p&gt;At this point, there are many different options to attack this problem but
many of them add unnecessary complexity.  You might be tempted to integrate
with a shiny new configuration parameter store or try to parse remote 
Terraform states and whatnot.&lt;/p&gt;

&lt;p&gt;However, there is an old, well-proven technology for this purpose: DNS. In
fact, there is a specific kind of DNS record for this purpose. It’s called
SRV and it was introduced &lt;a href=&quot;https://tools.ietf.org/html/rfc2782&quot;&gt;more than 20 years ago&lt;/a&gt;.  Applied to the
previous example, you will have one SRV record per Cassandra node, for example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;_cassandra._tcp.example.internal.   300 IN SRV 0 0 9042 c-123.example.internal.
_cassandra._tcp.example.internal.   300 IN SRV 0 0 9042 c-333.example.internal.
_cassandra._tcp.example.internal.   300 IN SRV 0 0 9042 c-234.example.internal.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These records are read in this way:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Name. DNS name to use when resolving.&lt;/li&gt;
  &lt;li&gt;Timeout in seconds. In this case, 5 minutes in seconds.&lt;/li&gt;
  &lt;li&gt;Class. It’s always IN for SRV records.&lt;/li&gt;
  &lt;li&gt;Type. SRV!&lt;/li&gt;
  &lt;li&gt;Priority. For clusters like Cassandra it makes sense to have the same 
priority for all nodes. The lower, the most priority.&lt;/li&gt;
  &lt;li&gt;Weight. This is useful to assign different fractions of the load to 
different servers but, as with priority, it makes sense to use the same 
value for all nodes of a Cassandra cluster.&lt;/li&gt;
  &lt;li&gt;Port.&lt;/li&gt;
  &lt;li&gt;Host name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can keep these records updated in many ways. For example, if you use 
Terraform, Cloud Formation or any other software defined infrastructure,
you can define the SRV records as linked to the node names. That way, any
infrastructure change will automatically change the records.&lt;/p&gt;

&lt;p&gt;Another common use case nowadays are services managed within Kubernetes.
Because Kubernetes embraces DNS as an integral part to service discovery, you
get &lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#srv-records&quot;&gt;SRV records for free for services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The only missing piece in the puzzle is that our connectors resolve the SRV
names.  Fortunately, we don’t need to modify existing connectors but we can
write a &lt;a href=&quot;https://kafka.apache.org/20/javadoc/org/apache/kafka/common/config/provider/ConfigProvider.html&quot;&gt;ConfigProvider&lt;/a&gt; implementation to add support for
any connector.&lt;/p&gt;

&lt;p&gt;As you &lt;a href=&quot;https://github.com/sortega/connect-dns-provider/blob/master/src/main/java/org/refeed/kafka/config/DnsConfigProvider.java&quot;&gt;can see&lt;/a&gt;, a simple single class is able to do the work. Because
this might be useful for more people and I never before published libraries
to Maven Central I took the pain to properly publishing it (GPG setup, opening
JIRA tickets&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;). You can find usage instructions at the
&lt;a href=&quot;https://github.com/sortega/connect-dns-provider&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Remember, let DNS do what DNS does. Even if it’s a “boring” technology.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In one of the many official videos explaining the “simple process”, there was an amazing comment of someone comparing the process US immigration redtape &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 18 Feb 2021 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/development/2021/02/18/dns/</link>
        <guid isPermaLink="true">http://sortega.github.io/development/2021/02/18/dns/</guid>
      </item>
    
      <item>
        <title>Improv: lessons for life</title>
        <description>
&lt;p&gt;Why are some conversations engaging, smoothly moving from point to point while
others die off in a couple of round-trips and a final monosyllable? Why can you
rapidly build chemistry with some people and have false starts with
others?&lt;/p&gt;

&lt;div style=&quot;width: 35%; margin: 1em 2em 1em 1ex; text-align: center; float: left; font-size: 90%&quot;&gt;
  &lt;a href=&quot;https://www.escueladeimprodebarcelona.com/&quot;&gt;
    &lt;img src=&quot;/assets/impro/impro.webp&quot; alt=&quot;Logo escuela de impro de Barcelona&quot; /&gt;
    I've been taking classes here ☝️
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Lately I’ve been taking some improvisation theater classes, &lt;em&gt;improv&lt;/em&gt; for
connoisseurs, and the experience has shed some light on these questions and
proven useful for the &lt;em&gt;real-life world™&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;First, improv is more about self-expression and play than about performing theater
in front of an audience, at least at the amateur level.  Your typical class
has an initial warm-up phase in which some exercises wake you up by
physically moving, interacting, or maybe shouting and then you play some
games in which you practice the different skills you need to improvise scenes.
Finally, you play some improvisation games in which everything is
unpredictable but within some guidelines.&lt;/p&gt;

&lt;p&gt;For example, one popular improv game called the statues consists of having 
someone freeze in a pose and then a new actor steps in and starts a scene
somehow using such a pose to justify it.  At some random point, the teacher will clap
and both actors will freeze.  Then the cycle restarts when a third actor
replaces one of the frozen ones.  This exercise is a constant surprise as
the photo finish of a scene that started with skiing becomes a
do-you-wanna-marry-me one and so on.&lt;/p&gt;

&lt;p&gt;This game is representative of elements in improv: some structure or rules,
a ton of unpredictability, a sense of building something together and the joy
of letting yourself play like you were a child again.&lt;/p&gt;

&lt;p&gt;As I’m a total &lt;em&gt;noob&lt;/em&gt; and the course is introductory, we focus on the
fundamentals that can be summarized as accepting and adding or with the motto
&lt;em&gt;yes and…&lt;/em&gt;.  This was surprising to me as I was expecting something more
related to acting but it makes a lot of sense.  Usually you improvise in
pairs or bigger groups and when someone proposes something it’s of paramount
importance to be generous and selfless in order to &lt;em&gt;accept&lt;/em&gt; that proposal, not doing
so breaks the flow and destroys the spirit of the game. In improv’s jargon it’s
called &lt;em&gt;negation&lt;/em&gt; and recognizing and avoiding it is one of the first things 
you are taught.&lt;/p&gt;

&lt;p&gt;Negation is the ultimate wet-blanket. Imagine that one actor braces herself
and say “It… it’s veery cold up here in the mo-mountain”; then the other 
negates her with “I’m a fish in the ocean.”  The first actor will be
disoriented not knowing what to do… even angry at her companion.&lt;/p&gt;

&lt;p&gt;Compare this with the opposite to negation: accepting and building on top of that.
“It… it’s veery cold up here in the mo-mountain” followed by “Don’t falter
now that we are so close to top of the Everest and to win &lt;em&gt;the bet&lt;/em&gt;”. Now, the
first actor can fill in more details about that enigmatic bet.&lt;/p&gt;

&lt;p&gt;Apart from having learned some jargon like negation, PROL&lt;sup id=&quot;fnref:prol&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:prol&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, bouncing;
and from having had a ton of fun I got a lesson to apply back to my regular
life: &lt;em&gt;yes and…&lt;/em&gt; is the missing ingredient to make conversations more
engaging and to build chemistry faster in some other situations. Think about
this: who do you prefer to go on in a holiday trip with? With someone that accept
other’s proposals and build on top of them or with someone that
systematically rejects anything but his or her own verbatim will?&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:prol&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;PROL: &lt;em&gt;Persona&lt;/em&gt;, Role, Objective and Locale &lt;a href=&quot;#fnref:prol&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 26 Dec 2019 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/peopleware/2019/12/26/impro/</link>
        <guid isPermaLink="true">http://sortega.github.io/peopleware/2019/12/26/impro/</guid>
      </item>
    
      <item>
        <title>Can't someone else do it?</title>
        <description>
&lt;p&gt;An automatic formatting tool is better than quibbling at formatting issues in pull requests. Why
paying attention to something that can be automatically minded for? &lt;strong&gt;Can’t someone else do it?&lt;/strong&gt;
That’s the reason we use &lt;a href=&quot;https://scalameta.org/scalafmt/&quot;&gt;scalafmt&lt;/a&gt; where I work.&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/scalafmt/cant-someone-else-do-it.png&quot; alt=&quot;Homer Simpson touting: 'Can't SOMEONE else DO it?'&quot; style=&quot;width: 50%&quot; /&gt;
    &lt;p style=&quot;text-align: center; font-size: 90%&quot;&gt;
    Why formatting the code yourself when someone else can do it (automatically)?
    &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Now IntelliJ has direct support for scalafmt, not so long ago I needed to use a separate plugin for
that. But there is a small problem. There are small corner cases in which the IDE-triggered reformat
doesn’t reformat stuff than the SBT-triggered one would do. Therefore, from time to time, the
Jenkins build complains about my pull requests for having files incorrectly formatted…&lt;/p&gt;

&lt;h2 id=&quot;not-anymore&quot;&gt;Not anymore!&lt;/h2&gt;

&lt;p&gt;Let’s remove the frustration of needed to wait again for the Jenkins build from time to time!
(This instructions are tailored for OS X, feel free to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get&lt;/code&gt; or equivalent
for your system).&lt;/p&gt;

&lt;p&gt;First, we are installing &lt;a href=&quot;http://www.martiansoftware.com/nailgun/&quot;&gt;nailgun&lt;/a&gt;, a protocol and server that solves the problem of long
initialization times for JVM executables. With nailgun you have a background JVM process that is
already started and ready to execute scalafmt or any other program with nailgun support.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nailgun
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, we are installing scalafmt standalone with nailgun support so that we can reformat or check
formatting from other scripts:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;coursier bootstrap &lt;span class=&quot;nt&quot;&gt;--standalone&lt;/span&gt; org.scalameta:scalafmt-cli_2.12:2.0.1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; sonatype:snapshots &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; /usr/local/bin/scalafmt_ng &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--main&lt;/span&gt; com.martiansoftware.nailgun.NGServer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To guarantee that the server is always running whenever we login we can use a &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/Introduction.html&quot;&gt;launchd&lt;/a&gt;
agent (launchd is the evolution and replacement of initd in the Darwin family of Unix). To do so,
we should create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/Library/LaunchAgents/scalafmt_ng.plist&lt;/code&gt; with this contents:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; 
          &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;plist&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;KeepAlive&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;scalafmt_ng&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/usr/local/bin/scalafmt_ng&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we restart our session or run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;launchctl load scalafmt_ng.plist&lt;/code&gt; the nailgun server will be
ready for service.&lt;/p&gt;

&lt;p&gt;Finally, we can write a &lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks&quot;&gt;git hook&lt;/a&gt; to check that our files are properly formatted:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Check but don't reformat sources with scalafmt&lt;/span&gt;
ng org.scalafmt.cli.Cli &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--non-interactive&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--git&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--test&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; .scalafmt.conf &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt; target &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-iname&lt;/span&gt; scala &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; d | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; target | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; bloop&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I have this file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.githooks/scalafmt-check&lt;/code&gt; to avoid duplication. To enable these checks for
a repo I simply link it to the pre-commit and pre-push hooks:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;repo
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ~/.githooks/scalafmt-check .git/hooks/pre-commit
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ~/.githooks/scalafmt-check .git/hooks/pre-push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can instantly know whether we are trying to commit/push code that is not well formatted:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Test commit&quot;&lt;/span&gt;
Looking &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;unformatted files...
All files are formatted with scalafmt :&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you prefer to reformat on commit you can go with almost the same script excluding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--test&lt;/code&gt;
flag.&lt;/p&gt;

&lt;h2 id=&quot;the-moral-of-the-story&quot;&gt;The moral of the story&lt;/h2&gt;

&lt;p&gt;Remove frustration and friction from your daily life. You’ll be happier and more productive!&lt;/p&gt;
</description>
        <pubDate>Sat, 17 Aug 2019 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/tools/2019/08/17/scalafmt/</link>
        <guid isPermaLink="true">http://sortega.github.io/tools/2019/08/17/scalafmt/</guid>
      </item>
    
      <item>
        <title>A way out of the Jar Hell</title>
        <description>
&lt;p&gt;A couple of weeks ago, a friend retweeted the release announcement of Debian 10:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Debian 10 buster has been released! &lt;a href=&quot;https://t.co/Qm1Oc7SXiF&quot;&gt;https://t.co/Qm1Oc7SXiF&lt;/a&gt;&lt;/p&gt;&amp;mdash; The Debian Project (@debian) &lt;a href=&quot;https://twitter.com/debian/status/1147683799393636355?ref_src=twsrc%5Etfw&quot;&gt;July 7, 2019&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;First thought: it has taken a couple of years but here it is.&lt;/p&gt;

&lt;p&gt;Second thought: these people know how to curate software… wait, my spider-sense is tingling crazy.&lt;/p&gt;

&lt;p&gt;And then I realized the connection between how the Debian project solves certain projects around
software ecosystem curation and some of the least happy parts of the life of the Scala developer:
the trouble with libraries, mainly binary compatibility problems.&lt;/p&gt;

&lt;h2 id=&quot;library-galore-perils&quot;&gt;Library galore perils&lt;/h2&gt;

&lt;p&gt;It can be argued that the single factor that makes modern development–with Scala or otherwise–more 
productive is the extensive use of tons and tons of open source libraries.
What in other times would have required months of development is today a handful
of lines of code depending on tens of libraries&lt;sup id=&quot;fnref:transitive&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:transitive&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;However, this powerful practice carries the seeds of important problems that can curtail its
benefits. Out of the many possible perils of the profuse use of libraries, most of them
are given short shrift by the development team as if they were not our responsibility.
Take a look at the skeletons in our closet:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Licensing&lt;/strong&gt;. There are many kinds of software licenses and more than one definition of open 
source out there&lt;sup id=&quot;fnref:open-source&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:open-source&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. Some of the licenses impose restrictions on the systems those libraries 
integrate to (e.g. GPLv3) and we cannot equate &lt;em&gt;“I can download it from Maven central”&lt;/em&gt; with
&lt;em&gt;“I can use it freely”&lt;/em&gt;.&lt;/p&gt;

    &lt;p&gt;There is an SBT plugin to quickly check the licenses of your dependencies called 
&lt;a href=&quot;https://github.com/sbt/sbt-license-report&quot;&gt;sbt-license-report&lt;/a&gt;. Most of the licenses are detected and
classified (e.g. Apache, GPL with Classpath Exception) but in some cases, the information
is missing from Maven Central and you will need to do a manual check.&lt;/p&gt;

  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Library quality&lt;/strong&gt;. Not all the code that is released as libraries meets the
same standards of quality. Even when meeting high standards, the
assumptions or the focus of the library can be far from the design of your
application, making you work around the library design doing circuitous
designs. Sometimes we want a banana, but the library we have found has a
&lt;a href=&quot;https://www.johndcook.com/blog/2011/07/19/you-wanted-banana/&quot;&gt;giant gorilla holding the banana&lt;/a&gt;. Think about this gorilla as concepts
unrelated with your application and bugs (in the library or its transitive
dependencies).&lt;/p&gt;

    &lt;p&gt;Adopting libraries should not be done blithely but after a cost-benefit
analysis. Remember the &lt;a href=&quot;https://en.wikipedia.org/wiki/Sturgeon's_law&quot;&gt;Sturgeon’s revelation&lt;/a&gt;: 90% of anything,
including libraries, is crap.&lt;/p&gt;

  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;. It’s not just that we are inheriting bugs and design warts from
the libraries we use, we are increasing the surface area for security.&lt;/p&gt;

    &lt;p&gt;A cautionary tale from last year happened around NPM, the main library repository
for the Javascript ecosystem.  Dominic Tarr, the maintainer of a widely used
library, decided to open the project to more people because &lt;a href=&quot;https://github.com/dominictarr/event-stream/issues/116#issuecomment-440927400&quot;&gt;he wasn’t even
using it anymore&lt;/a&gt;, he was doing it for free and someone volunteered
to do it for him. Unfortunately, the person volunteering was a black hat hacker
that released a version of the library with some code targeting Copay, a Bitcoin
wallet, that indeed &lt;a href=&quot;https://www.zdnet.com/article/hacker-backdoors-popular-javascript-library-to-steal-bitcoin-funds/&quot;&gt;got released with the malicious code&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;This kind of horror story is less likely to happen for libraries better staffed
in which you need to have a track record to become a committer. However,
in the long tail of libraries out there, don’t expect all projects to have these
practices. In the end, the chain is as weak as the security of the weakest library
you depend upon.&lt;/p&gt;

    &lt;p&gt;While it’s impossible to avoid not yet known security problems, aka 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Zero-day_(computing)&quot;&gt;zero-day vulnerabilities&lt;/a&gt;, these are reported by the security community
to the &lt;a href=&quot;https://cve.mitre.org/&quot;&gt;CVE&lt;/a&gt; database that can be checked automatically from SBT with the
&lt;a href=&quot;https://github.com/albuch/sbt-dependency-check&quot;&gt;sbt-dependency-check&lt;/a&gt; plugin. You can even make your build
fail with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dependencyCheckFailBuildOnCVSS&lt;/code&gt; command.&lt;/p&gt;

  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Compatibility issues&lt;/strong&gt;. Unlike the previous ones, this problem can’t be overlooked because
when we have a library compatibility problem, like the typical binary compatibility issue like
the feared &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncompatibleClassChangeError&lt;/code&gt; our code refuses to work. You can ignore
that one of your libraries has a license you are violating but not fixing a conflict of versions 
is like spurring a dead horse. Congratulations, you are enjoying a JAR Hell!
Way more about this in the next section.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these problems get amplified by the fact that when we decide to marry one
library we are not marring just that library but all its family: potentially
many transitive dependencies. You need to check the licenses of all those libs,
evaluate their quality, monitor its CVE’s and pray for them not to have a
version conflict with the other libraries you are using.&lt;/p&gt;

&lt;h2 id=&quot;compatibility-problems&quot;&gt;Compatibility problems&lt;/h2&gt;

&lt;p&gt;To illustrate why we have this library compatibility problem let’s use a simplified example.
Imagine you have an application that has two direct dependencies libraries a and b. Both direct
dependencies depend on library c but–to our despair–not the same version.&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/jarhell/0_intended_dependencies.png&quot; alt=&quot;Dependency diagram in which your app depends on a 1.2 and b 2.1. Library a depends on c 1.1 and library b con c 2.2&quot; style=&quot;width: 40%&quot; /&gt;
    &lt;p style=&quot;text-align: center&quot;&gt;
    Dependencies as intended
    &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;When we run our program, we cannot have two versions of the same library (unless using OSGi) and
version 1.1 of c is evicted in favor of the other one.&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/jarhell/1_actual_dependencies.png&quot; alt=&quot;Similar to the previous diagram but a is now depending on c 2.2 and its original dependency is evicted&quot; style=&quot;width: 40%&quot; /&gt;
    &lt;p style=&quot;text-align: center&quot;&gt;
    Dependencies in runtime
    &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;When a dependency eviction is a problem? When the assumptions made by the code depending on the
evicted library are not met by the one used in runtime. There are two types of problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Binary compatibility problems&lt;/strong&gt;. Our Java/Scala code gets compiled to bytecode that invokes
specific methods with some number of parameters of some definite types. If c 2.2 adds a new
argument to some method that a is invoking, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoSuchMethodException&lt;/code&gt; will be raised. If the
whole class has been renamed or removed, then a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClassNotFoundException&lt;/code&gt; one. And if a static
method is converted to a normal one, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncompatibleClassChangeError&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Semantic compatibility problems&lt;/strong&gt;. Even if the public signatures of library c don’t change
we can face compatibility problems because some assumptions are not captured by method signatures.
For example, we might have a class in c with a constructor with default values that might change
between versions completely changing what library a is asking c to do. This is trickier to
diagnose that an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncompatibleClassChangeErrors&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In an ideal world, we will have libraries with &lt;a href=&quot;https://semver.org/&quot;&gt;semantic versioning&lt;/a&gt;, which is a convention
directed towards making our lives as consumers of libraries easier:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Given a version number MAJOR.MINOR.PATCH, increment the:

  MAJOR version when you make incompatible API changes,
  MINOR version when you add functionality in a backwards-compatible manner, and
  PATCH version when you make backwards-compatible bug fixes.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If all libraries were following this versioning system it would be easier to manage evictions as
you’ll be sure that c 1.2 could be safely replaced by c 1.9. However, it’s difficult that this
ever happens because you can check binary compatibility in an automated fashion&lt;sup id=&quot;fnref:mima&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:mima&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; but semantic
compatibility is more elusive.&lt;/p&gt;

&lt;p&gt;Another practice that helps mitigate this problem is to reduce the number of dependencies by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Not using libraries unless they pay for its salt.&lt;/li&gt;
  &lt;li&gt;Use of granular libraries. Having a “commons” library that depends on many, many other things
is a really bad idea as you are bringing all those even if you just wanted a small piece of
the functionality. It’s better to have “commons-streaming”, “commons-kafka”, etc.&lt;/li&gt;
  &lt;li&gt;Relying on the platform. Can you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.time&lt;/code&gt; instead of a third-party library? Is anything
solving my problem in the Scala collections library? By platform I don’t just mean the JDK and
Scala’s library, this might include the libraries bundled with Spark or any other platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;solving-compatibility-problems&quot;&gt;Solving compatibility problems&lt;/h2&gt;

&lt;p&gt;The typical modus operandi when facing a library compatibility problem is first, finding the
libraries whose dependencies get evicted. Second, trying to bump or downgrade one of them in order
for the dependencies to get close enough the problem is fixed. Third, if that doesn’t work, fork
one of them to produce a custom version whose dependencies are aligned with the rest of our
microcosm&lt;sup id=&quot;fnref:forking&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:forking&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Another solution consists of actually allowing two versions of a library in runtime. That is
possible in the JVM because class management is delegated to class loaders. &lt;a href=&quot;https://www.osgi.org&quot;&gt;OSGi&lt;/a&gt; is a framework
that leverages this to allow multiple versions of a library with some caveats. With OSGi, you need
to annotate which packages of the library are public, being the rest private and not accessible
(this plays very bad with reflection-based frameworks). As long as a library don’t expose any type
of its dependencies in its public part that dependency can be hidden from other modules and you can
have multiple versions of it.&lt;/p&gt;

&lt;p&gt;Is then OSGi a solution? It is for most cases but you are paying for it with more complexity in
dependency management, will have problems with anything relying on reflection and for some cases,
you will need to still fork some libraries.&lt;/p&gt;

&lt;p&gt;Another possible mitigation that doesn’t solve this problem but can greatly
reduce its impact is the use of microservice architectures. In such
architectures, each service has a narrow business purpose and that corresponds
to a subset of the dependencies that the equivalent monolith whould have had.
However, this is not automatically true as some microservice ecosystems tend
to share many, many shared libraries and you get the worst of both worlds:
lots of dependency conflicts and coupling like in the monolith case and you
need to cope with distributed systems complexities as in any microservice
ecosystem. This anti-pattern is known as the &lt;a href=&quot;https://www.infoq.com/news/2016/02/services-distributed-monolith/&quot;&gt;distributed
monolith&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;is-there-any-way-out-of-the-jar-hell&quot;&gt;Is there any way out of the JAR Hell?&lt;/h2&gt;

&lt;p&gt;Lately, I’ve been wasting quite some time impeded by binary compatibility
problems and I became close to convinced that they were an inevitable part
of the life of the Scala programmer very much like NPEs for the Java programmer.
Is there any solution? Should we suffer these problems as a way to atone our
promiscuous library sins?&lt;/p&gt;

&lt;div style=&quot;margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/jarhell/jar_hell.jpg&quot; alt=&quot;Hide-your-pain Harold is holding a bottle with 'jar hell' written in bright red letters&quot; style=&quot;width: 50%&quot; /&gt;
    &lt;p style=&quot;text-align: center&quot;&gt;
    Should we act like the JAR Hell is inevitable?
    &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;A workable approach to these problems was hidden in plain sight!  When I saw the Debian 10 release 
announcement I was thunderstruck by the revelation: Debian has been solving these problems for
decades!&lt;/p&gt;

&lt;p&gt;If you think about it, a Debian release is a set of packages (libraries) that comply with some
license requirements&lt;sup id=&quot;fnref:oss&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:oss&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; and work well together. Those packages are curated by a bunch of maintainers
that form a community and you need to be verified in person to get into (so it’s unlikely that
something like the NPM problem happens to them).&lt;/p&gt;

&lt;p&gt;A release of Debian is created by getting fresh versions of the core packages (kernel, libc,
buildtools) and then, aligning everything else. They have tooling that makes very easy to manage
patches on top of the original code (“upstream” in Debian parlance). Those patches are used to
fix compatibility problems, make default behavior more Debian-like or fix other problems.&lt;/p&gt;

&lt;p&gt;After the release is out, packages are frozen except for security patches. These are, by design, 
things you can trust to update automatically with confidence that nothing is going to break.
Interfaces won’t change, configuration formats won’t change. You just get security patches. These 
are sometimes provided by the upstream developers and, other times by the Debian maintainers.&lt;/p&gt;

&lt;p&gt;What happens if I need the latest version of a library for a release of Debian that has an older 
version? You can always compile it against what is shipped in that release. However, as this is very
common, the work of changing dependencies and fixing compilation is shared in dedicated  “backport”
repositories.&lt;/p&gt;

&lt;p&gt;Cool. Can I have this for Java/Scala? We have examples of limited versions of this. For instance,
the &lt;a href=&quot;https://spring.io&quot;&gt;Sprint Boot&lt;/a&gt; community does this kind of curation for Spring-based applications. They
have dozens of &lt;a href=&quot;https://www.javatpoint.com/spring-boot-starters&quot;&gt;“starter” modules&lt;/a&gt; that are a selection of concrete libraries in versions 
that work well with each other. For instance, mix in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-boot-starter-data-couchbase&lt;/code&gt; and 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-boot-starter-data-cassandra&lt;/code&gt; and you won’t have compatibility problems. However, it is
useful only with the premise of building a Spring application and limited in scope.&lt;/p&gt;

&lt;p&gt;A promising tool that is in development for the Scala ecosystem is &lt;a href=&quot;https://twitter.com/propensive&quot;&gt;Jon Pretty&lt;/a&gt;’s 
&lt;a href=&quot;https://fury.build/concepts&quot;&gt;Fury&lt;/a&gt;, a replacement for SBT. An integral concept on Fury is the &lt;em&gt;layer&lt;/em&gt;, “a collection of 
related projects you are working on” and each project can reference the upstream repository of an 
external library or an internal artifact. Layers can be potentially shared to form the basis for a 
curation similar to what the Debian project does.&lt;/p&gt;

&lt;h2 id=&quot;time-to-mature&quot;&gt;Time to mature&lt;/h2&gt;

&lt;p&gt;Getting out of the JAR hell is a matter of maturity. Using so many libraries so liberally has multiplied
developer productivity to a large extent but without the restraint of some
curation culture like the one in Debian, its risks and practical problems might
cancel out the advantages of having access to this galore of functionality.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated on 2019-08-17:&lt;/em&gt; mention microservices as a mitigation inspired by
&lt;a href=&quot;https://disqus.com/by/trylks/&quot;&gt;trylks&lt;/a&gt;’s comment&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:transitive&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;And it’s transitive dependencies! It’s not uncommon to have hundreds of them in a single small project. &lt;a href=&quot;#fnref:transitive&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:open-source&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;The original definition of &lt;a href=&quot;https://www.fsf.org/about/what-is-free-software&quot;&gt;free software&lt;/a&gt; by Richard Stallman and the &lt;a href=&quot;https://www.fsf.org&quot;&gt;FSF&lt;/a&gt;, and the more corporate-friendly, &lt;a href=&quot;https://opensource.org/docs/osd&quot;&gt;open source definition&lt;/a&gt; by the &lt;a href=&quot;https://opensource.org/&quot;&gt;OSI&lt;/a&gt;. &lt;a href=&quot;#fnref:open-source&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:mima&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;For example, the SBT’s plugin &lt;a href=&quot;https://github.com/lightbend/mima&quot;&gt;mima&lt;/a&gt; allows you to check for binary compatibility against previous versions of the library you are developing &lt;a href=&quot;#fnref:mima&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:forking&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;If you do this, please use good conventions to avoid confusing your coworkers. For example, if you fork some library in version 1.2.2 to align versions, release it on your private artifact repo as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.2.2-our-company&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.2.3&lt;/code&gt;. The former is obviously some private customization and the later is bound to collide with the real thing soon enough. &lt;a href=&quot;#fnref:forking&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:oss&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Open source. What happens with closed software? It’s not integrated by the Debian
    community but it benefits greatly of this model of releases because you just need to compile your 
    libraries/programs against each recent Debian release and provide a repository URL. No need to 
    create a binary that is statically linked against all libraries (this is analogous to the fat-jar 
    anti-pattern). &lt;a href=&quot;#fnref:oss&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 27 Jul 2019 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/development/2019/07/27/jar-hell/</link>
        <guid isPermaLink="true">http://sortega.github.io/development/2019/07/27/jar-hell/</guid>
      </item>
    
      <item>
        <title>Finatra meets Ammonite</title>
        <description>
&lt;div style=&quot;width: 80%; margin: 1em auto; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/embed-ammonite/finatra-meets-ammonite.png&quot; alt=&quot;Finatra meets Ammonite&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://www.lihaoyi.com/&quot;&gt;Li Haoyi&lt;/a&gt;’s &lt;a href=&quot;https://ammonite.io/&quot;&gt;Ammonite&lt;/a&gt; is the most user-friendly Scala REPL out there.
It has a more than decent syntax highlight, you can edit multi-line snippets, search the command
history, auto-complete expressions and much more!&lt;/p&gt;

&lt;p&gt;It’s remarkable how you can fiddle with a library without the hassle of creating a SBT project 
thanks to the magic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ivy&lt;/code&gt; imports. Let’s say you want to try out some scalaz 7.2.23 for some
reason:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amm&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Welcome&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ammonite&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Repl&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scala&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Java&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_161&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;please&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;support&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;our&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;www&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;patreon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lihaoyi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;$ivy.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;`org.scalaz::scalaz-core:7.2.23`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;scalaz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Scalaz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;_&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;$ivy.$&lt;/span&gt;                               &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;scalaz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Scalaz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;_&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;'a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;'b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|+|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;'a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;'c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;res1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;'a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;'c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;'b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Importing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ivy.`org.scalaz::scalaz-core:7.2.23`&lt;/code&gt; is equivalent to adding 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;org.scalaz&quot; %% &quot;scalaz-core&quot; % &quot;7.2.23&quot;&lt;/code&gt; to SBT’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libraryDependencies&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ammonite can be &lt;a href=&quot;https://ammonite.io/#Embedding&quot;&gt;embedded&lt;/a&gt; in other applications and I find it useful to so when
developing &lt;a href=&quot;https://twitter.github.io/finatra/&quot;&gt;Finatra&lt;/a&gt; services.&lt;/p&gt;

&lt;p&gt;There are two interesting ways of doing the integration: as a &lt;strong&gt;local development console&lt;/strong&gt; for 
debugging and exploration or as a mechanism to inspect or operate against &lt;strong&gt;remote services&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;give-your-finatra-service-a-development-console&quot;&gt;Give your Finatra service a development console&lt;/h2&gt;

&lt;p&gt;If you have ever used Rails and enjoyed it, you will be offended when facing development
environments in which you cannot start a console and tinker with domain services, the database,
etc.  The first step to get Ammonite integrated into Finatra &lt;em&gt;a la Rails&lt;/em&gt; is to depend on
Ammonite with test scope so add to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.sbt&lt;/code&gt; this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;com.lihaoyi&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ammonite&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;versions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ammonite&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cross&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CrossVersion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;full&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;versions.ammonite&lt;/code&gt; is a recent version (e.g. 1.4.0).&lt;/p&gt;

&lt;p&gt;The idea is to have an alternative main class under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/test&lt;/code&gt; that will start the service and the
console. To make it easier, you might create an alias in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.sbt&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;fork&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;addCommandAlias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;run-with-console&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test:runMain ammonite.integration.ConsoleLauncher&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we are using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ammonite.integration&lt;/code&gt; package. This is important because we need
to use some definitions that are package-private and only available from such package.&lt;/p&gt;

&lt;p&gt;Then, you should create the launcher class. It should similar to your actual entry point (usually a
server class extending from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.twitter.finatra.http.HttpServer&lt;/code&gt; and a handful of Guice modules)
but instantiating Ammonite.&lt;/p&gt;

&lt;p&gt;Let’s take a look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleLauncher&lt;/code&gt; bit by bit.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ammonite.integration&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.google.inject.Module&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.yourcompany.project.infrastructure.Server&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.yourcompany.project.modules.FooModule&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.yourcompany.project.modules.BarModule&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConsoleLauncher&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;modules&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;modules&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nc&quot;&gt;FooModule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nc&quot;&gt;BarModule&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nothing special up to here.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prelude&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
import scala.concurrent._
import scala.concurrent.duration._

implicit class ExtendedFuture[A](val f: Future[A]) {
  def await: A = Await.result(f, Duration.Inf)
}
&quot;&quot;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can add a custom prelude to Ammonite. You can add common imports or even functions and implicit
conversions here. This prelude allows me to easily use services returning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; in the console.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;postWarmup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;postWarmup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predefCode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;verboseOutput&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;injector&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FooService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, we instantiate the console. Note that we are exposing the Guice dependency injector so
we can lookup any component of our service in the console. For common things we can directly bind 
then to a name, exactly like the sample &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FooService&lt;/code&gt; is bound to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sbt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;idea&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sbt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sbt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plugins&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sebastian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ortega&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sbt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plugins&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Updating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProjectRef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;file:/Users/sebastian.ortega/.sbt/1.0/plugins/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;global-plugins&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Done&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;updating&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sbt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;definition&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sebastian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ortega&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;project&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sbt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;custom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;feed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sebastian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ortega&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Scala&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sources&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Java&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sources&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sebastian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ortega&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scala&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Done&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packaging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;replBridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DefaultPredef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ArgsPredef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sebastian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ortega&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letgo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;custom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;feed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Welcome&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ammonite&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Repl&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scala&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Java&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_161&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;please&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;support&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;our&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;www&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;patreon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lihaoyi&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;checkHealth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;await&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;res1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Health&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Sick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cannot reach server&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Et voilà&lt;/em&gt;, no need to miss the Rails console anymore.&lt;/p&gt;

&lt;h2 id=&quot;remote-ammonite-powers&quot;&gt;Remote Ammonite powers&lt;/h2&gt;

&lt;p&gt;The other interesting way to integrate Ammonite into your service is as a remote console. That way
you can connect to a remote server in the stating or even production machines and fiddle with them.
Maybe not a very good idea… but power to the people!&lt;/p&gt;

&lt;p&gt;I’m going to demonstrate this approach by introducing a pluggable Guice module that you can include
or not in your server to enable or disable the server.&lt;/p&gt;

&lt;p&gt;We will need an additional dependency but this time will have compile scope instead of test scope.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;com.lihaoyi&quot;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ammonite-sshd&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;versions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ammonite&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cross&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CrossVersion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;full&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And a module named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AmmoniteServerModule&lt;/code&gt; under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/main/scala&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ammonite.integration&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;javax.inject.Singleton&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ammonite.sshd.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;SshServerConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SshdRepl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ammonite.util.Bind&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.google.inject.Provides&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.twitter.inject.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TwitterModule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.apache.sshd.server.config.keys.DefaultAuthorizedKeysAuthenticator&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.yourcompany.project.modules.FooModule&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AmmoniteServerModule&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TwitterModule&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prelude&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
import scala.concurrent._
import scala.concurrent.duration._

implicit class ExtendedFuture[A](val f: Future[A]) {
  def await: A = Await.result(f, Duration.Inf)
}
&quot;&quot;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We have some elements in common: same prelude and the class is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ammonite.integration&lt;/code&gt;
package. However, this is an independent Guice module.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;  &lt;span class=&quot;nd&quot;&gt;@Provides&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Singleton&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;providesAmmoniteServer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FooModule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SshdRepl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SshServerConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22222&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;publicKeyAuthenticator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DefaultAuthorizedKeysAuthenticator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SshdRepl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;replArgs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Bind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;injector&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Bind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The SSH server is defined as an application singleton (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Provides @Singleton&lt;/code&gt;) and configured to
listen in localhost on the port 22222 honoring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/authorized_keys&lt;/code&gt; as system’s SSH server.
Note also, how the injector and some services can be also bound for the session.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;singletonPostWarmupComplete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;singletonPostWarmupComplete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;SshdRepl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;singletonShutdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;SshdRepl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;singletonShutdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We need also to start/stop the server using some lifecycle callback methods.&lt;/p&gt;

&lt;p&gt;With this in place, we can SSH and enjoy of the same interactive experience as before but
potentially from the other side of the world:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22222&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;interpBridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;replBridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DefaultPredef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synthetic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ArgsPredef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sc&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Compiling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sebastian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ortega&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letgo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;custom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;feed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Welcome&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ammonite&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Repl&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scala&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Java&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_161&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ammonite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;please&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;support&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;our&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;www&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;patreon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lihaoyi&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;injector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BarService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BarService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;BarService&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cfe278&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;someAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;await&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;res1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello world&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Sun, 03 Feb 2019 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/development/2019/02/03/embed-ammonite/</link>
        <guid isPermaLink="true">http://sortega.github.io/development/2019/02/03/embed-ammonite/</guid>
      </item>
    
      <item>
        <title>Scala mangling versus Mockito</title>
        <description>
&lt;p&gt;One of the main strengths of Scala is that you can parasite the ecosystem of
libraries of Java and infrastructure and tooling of the JVM&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.  Of course,
this is not a free lunch as some gotchas of Scala come from that permeability
to Java (like nullability, universal equality and the like).&lt;/p&gt;

&lt;p&gt;Interop, or the ability or use Java code from Scala and vice versa, works
reasonably well in the Scala-calling-Java direction and not so well in the
opposite direction and that is a conscious design decision of the language. To
understand why, we need to deep dive in how Scala and Java share the JVM.&lt;/p&gt;

&lt;h2 id=&quot;name-mangling&quot;&gt;Name mangling&lt;/h2&gt;

&lt;p&gt;In order to execute in the JVM, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scalac&lt;/code&gt; is forced to compile to the same
bytecode and artefacts that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javac&lt;/code&gt;.  Scala concepts that can be mapped
directly to Java are no surprise. For instance, you are going to see something
like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def square(n: Int): Int&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int square(int n)&lt;/code&gt; from Java. But, what
about concepts that cannot be cleanly mapped?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Origin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This little snipped is going to be compiled into two classes: an unsurprising
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point.class&lt;/code&gt; and a more interesting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point$.class&lt;/code&gt;. Scala’s compiler needs to
generate a class for the companion object and it’s using the reserved
character &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt;&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; to avoid colliding with user defined names. This process is
called &lt;a href=&quot;https://en.wikipedia.org/wiki/Name_mangling&quot;&gt;name mangling&lt;/a&gt; and is at least as older as compilers are.&lt;/p&gt;

&lt;p&gt;Using &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javap.html&quot;&gt;javap&lt;/a&gt; we can take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; files:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;javap &lt;span class=&quot;s1&quot;&gt;'Point$.class'&lt;/span&gt;
Compiled from &lt;span class=&quot;s2&quot;&gt;&quot;Point.scala&quot;&lt;/span&gt;
public final class mockpost.Point&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;implements scala.Serializable &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  public static mockpost.Point&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;MODULE&lt;span class=&quot;nv&quot;&gt;$;&lt;/span&gt;
  public static &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  public mockpost.Point Origin&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  public mockpost.Point apply&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;int, int&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  public scala.Option&amp;lt;scala.Tuple2&amp;lt;java.lang.Object, java.lang.Object&amp;gt;&amp;gt;
    unapply&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mockpost.Point&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After looking at this it is evident&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; how to use the companion object from Java.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MODULE&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Origin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;Origin is at x=%d y=%d&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;leaky-abstractions-are-going-to-leak&quot;&gt;Leaky abstractions are going to leak&lt;/h2&gt;

&lt;p&gt;When mangling is a leaky abstraction? If you limit yourself to calling Java
code from Scala you need to consider mangling almost never. Almost.&lt;/p&gt;

&lt;p&gt;Recently I got bitten by this leaky abstraction&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; while using
&lt;a href=&quot;https://site.mockito.org/&quot;&gt;Mockito&lt;/a&gt; from Scala.  For the sake of simplicity (and to avoid
exposing my employer’s &lt;acronym title=&quot;Intellectual Property&quot;&gt;IP&lt;/acronym&gt;),
let’s see that we have this service interface:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Service&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We want to unit test this class that gets one instance of the service
injected:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OtherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parseTags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt;       &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;sum&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parseTags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;nonEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;nc&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;trim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;toMap&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that we have two cases to test: when tags are passed explicitly and when
a default argument is used.  Let’s say we write two test cases to cover both
cases:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;s&quot;&gt;&quot;Mocking service&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;work when all arguments are explicitly passed&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;v1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;k2&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;v2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OtherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k1:v1, k2:v2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;work when using default arguments&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OtherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What do we get when running them? The first passes but the second produces a
null pointer exception out of the blue.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[info] Mocking service
[info] - should work when all arguments are explicitly passed
[info] - should work when using default arguments *** FAILED ***
[info]   java.lang.NullPointerException:
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This kind of problem can be a huge time hole as the source of the exception is
literally invisible, in &lt;strong&gt;code we cannot see&lt;/strong&gt;.  Let’s use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javap&lt;/code&gt; on the
service (slightly cleaned up for readability):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Service&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request$default&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request$default&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Wow, default arguments become new “invisible” methods with a mangled name in
the form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;method_name&amp;gt;$default$&amp;lt;argument_pos&amp;gt;$&lt;/code&gt;&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;.  And we are not telling
Mockito to what to return in that case… so we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;workarounds-and-solutions&quot;&gt;Workarounds and solutions&lt;/h2&gt;

&lt;p&gt;There are several unsatisfactory workarounds we can use to overcome this gotcha:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We can avoid using default arguments in our production code. This is
difficult to enforce and frankly depressing.&lt;/li&gt;
  &lt;li&gt;We can expect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;s when mocking the main method of the service. Be
prepared to write an apologizing comment in your test.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;work when using default arguments&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// We are going to receive null instead of the default argument.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Sorry 'bout this. Trust me!&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OtherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;We can mock the default argument… from Java! I’m mentioning it just for
completeness (makes my eyes bleed!).&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MockitoHelper&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setupDefaultArguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Mockito&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$default&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MODULE&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, the real solution to this problem&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; is to use a mocking library
designed for Scala rather than Java. With &lt;a href=&quot;http://scalamock.org/&quot;&gt;ScalaMock&lt;/a&gt; both test
cases will work seamlessly:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;s&quot;&gt;&quot;Mocking service&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;work when all arguments are explicitly passed&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;expects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;v1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;k2&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;v2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;returning&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OtherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k1:v1, k2:v2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;work when using default arguments&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ignore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;expects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;returning&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OtherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;otherService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeTags&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Check out &lt;a href=&quot;https://github.com/sortega/mockpost&quot;&gt;this repo&lt;/a&gt; if you want to run this and the previous sample snippets.&lt;/p&gt;

&lt;p&gt;In conclusion, it’s wonderful to piggy-back on the JVM ecosystem but sometimes
we got bitten by leaky abstractions. It’s in those cases when knowing what’s
under the hood can save you hours of frustration.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;You can also parasite the Javascript ecosystem with &lt;a href=&quot;https://www.scala-js.org/&quot;&gt;scala.js&lt;/a&gt; or fly by yourself with &lt;a href=&quot;https://www.scala-native.org&quot;&gt;scala native&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;You can actually try to use it in your class and variable names but it might interfere with mangling. We can say that it is “reserved” in the spirit of JavaScript’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt; &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Evident but “ugly as a bare foot” as we say in Spanish &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Almost all abstractions are leaky. Almost. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;These names can grow so large when you have lambdas within lambdas that you might &lt;a href=&quot;https://issues.scala-lang.org/browse/SI-3623&quot;&gt;hit the path length limit of Linux&lt;/a&gt; &lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Apart from not using mocks… &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Fri, 19 Oct 2018 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/development/2018/10/19/mocking-in-scala/</link>
        <guid isPermaLink="true">http://sortega.github.io/development/2018/10/19/mocking-in-scala/</guid>
      </item>
    
      <item>
        <title>Viterbi search</title>
        <description>
&lt;p&gt;The Viterbi algorithm is an interesting example of a dynamic programming
algorithm that lies between memoized Fibonacci and &lt;a href=&quot;https://en.wikipedia.org/wiki/Levenshtein_distance&quot;&gt;Levenshtein distance&lt;/a&gt;
in complexity.  Like any other dynamic programming algorithm it is
characterized by having an asymptotic complexity way lower than the naïve
approach thanks to being able to divide the task at hand into subproblems that
tend to be repeated and are cached.&lt;/p&gt;

&lt;p&gt;In this case, the context of the Viterbi algorithm is a Markov chain that
models some system as a directed graph of states with some transition
probabilities. Reimplementing the example at the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Viterbi_algorithm&quot;&gt;relevant wikipedia page&lt;/a&gt; in Scala, let’s say that a patient can be
healthy or afflicted by a fever:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Health&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Health&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Good&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Health&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Feverish&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Health&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, we are not in a hospital and we cannot know for sure if the person is
really healthy or not, but we can observe the symptoms the person experiments
day by day:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symptom&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symptom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Normal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symptom&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Cold&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symptom&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Dizzy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symptom&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The Viterbi algorithm can be used only when we made some simplifying
assumptions. First, the link between the health status and the symptoms can be
modelled as a simple discrete probability distribution. Second, the health
status only depends on the status of the previous day (no more memory) by
another simple discrete probability. This is known as a hidden Markov chain
and it is amenable to beautiful&lt;sup id=&quot;fnref:ejem&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:ejem&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; charts:&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/viterbi/wikipedia_hmm.svg&quot; alt=&quot;Hidden Markov model&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Note how states are &lt;em&gt;hidden&lt;/em&gt; because of the indirection layer that the
symptoms represent.&lt;/p&gt;

&lt;p&gt;We can represent the same setup not so beautifully by means of some DSLish
modelling in Scala:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hidden&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HiddenMarkovChain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Health&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;](&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;prevalence&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Distro&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                      &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Feverish&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;hiddenChain&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Distro&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.7d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                          &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Feverish&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.3d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Feverish&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Distro&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.4d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Feverish&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;observationDistros&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Distro&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Normal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                          &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Cold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                          &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Dizzy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Feverish&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Distro&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Normal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Cold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Dizzy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we have all the pieces in place to really explain &lt;em&gt;what&lt;/em&gt; the Viterbi
algorithm does: given a sequence of symptoms, it &lt;em&gt;searches&lt;/em&gt; for the most
likely sequence of hidden states. For instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;nv&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;viterbiPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Normal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Cold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Dizzy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Feverish&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We might solve this problem by brute force by just running all the possible
sequences of states (2&lt;sup&gt;3&lt;/sup&gt;, s&lt;sup&gt;n&lt;/sup&gt; in general) to know their
probabilities, then finding the probability of each sequence to produce the
actual observations. Too bad we are talking about exponential
complexity making it impractical except for the smallest cases.&lt;/p&gt;

&lt;p&gt;The Viterbi search runs in just O(ns&lt;sup&gt;2&lt;/sup&gt;) where n is the length of the
sequence and s is the number of possible hidden states, a polynomial bargain!&lt;/p&gt;

&lt;p&gt;The trick, as in other dynamic programming algorithms is avoiding rework while
doing the search. The central fact making it possible is the Markov memoryless
property: state transitions depend just on the previous state. This means that
we can decompose the problem into:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Computing the most probable paths of length n-1 ending in each one of the
possible states.&lt;/li&gt;
  &lt;li&gt;Finding out what is the most likely extension of a path getting to each one
of the possible states.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we memoize this recursive function we get that attractive polynomial
execution time.&lt;/p&gt;

&lt;p&gt;An interesting point about the memoryless property of the Markov chain is that
new evidence can change our interpretation of the previous states even if each
state depends just on the previous state. Let’s illustrate it with a chain
with different, more extreme probabilities:&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 1em 0; text-align: center&quot;&gt;
    &lt;img src=&quot;/assets/viterbi/hmm.svg&quot; alt=&quot;Hidden Markov model&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;In this scenario, having low fever for a day is not evidence strong enough to
think that the patient is ill:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;nv&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;viterbiPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Normal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;LowFever&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, if there is high fever the third day our interpretation of what is
most likely changes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;nv&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;viterbiPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Normal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;LowFever&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;nv&quot;&gt;Symptom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;HighFever&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Good&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Incubating&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Health&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;Ill&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The implementation of the algorithm is &lt;a href=&quot;https://github.com/sortega/viterbi/blob/master/src/main/scala/viterbi/HiddenMarkovChain.scala&quot;&gt;surprisingly brief&lt;/a&gt; if you
have a monadic &lt;a href=&quot;https://github.com/sortega/viterbi/blob/master/src/main/scala/viterbi/Distro.scala&quot;&gt;discrete probability class&lt;/a&gt; to support it. Check
the code, or better, implement it yourself to solidify your understanding of
it.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:ejem&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;At least it is easier to grasp than loads of tables with numbers. &lt;a href=&quot;#fnref:ejem&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 29 Apr 2017 00:00:00 +0000</pubDate>
        <link>http://sortega.github.io/development/2017/04/29/viterbi/</link>
        <guid isPermaLink="true">http://sortega.github.io/development/2017/04/29/viterbi/</guid>
      </item>
    
  </channel>
</rss>
