<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/feed.xsl"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Intuitive Counter</title>
    <link>https://blog.walend.net/</link>
    <atom:link href="https://blog.walend.net/feed.xml" rel="self" type="application/rss+xml" />
    <description>David Walend&#39;s blog about Scala, AI, graphs, and coding</description>
    <language>en</language>
    <copyright>David Walend, CC BY 4.0</copyright>
    <lastBuildDate>Tue, 25 Aug 2026 00:00:00 +0000</lastBuildDate>
    <item>
      <title>A Centaur&#39;s Gait</title>
      <link>https://blog.walend.net/2026/08/centaur-hoofbeats/</link>
      <guid isPermaLink="true">https://blog.walend.net/2026/08/centaur-hoofbeats/</guid>
      <pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <category>AI</category>
      <category>Claude Code</category>
      <category>SDLC</category>
      <description>With Claude Code I&#39;m able to code faster hour-by-hour, but at very uneven pace. I configured hooks to play a tone when Claude Code needs my attention.</description>
      <content:encoded><![CDATA[<p>Using an LLM has changed the rhythm of how I work on a minute-by-minute scale. It bothered me at first, but I've figured out some things. In the spirit of ((((Do something!) small) useful) Now!) from ascii inventor Bob Bemer:</p>
<h2 id="tldr">TL/DR</h2>
<p>Get Anthropic Claude Code to play an alert tone when it needs your attention by adding <a href="https://blog.walend.net/2026/08/centaur-hoofbeats/#boink">these hooks</a> to your <code>~/.claude/settings.json</code>. Changing over to AI-assisted coding means I work faster, but also at a much less regular pace. Having Claude play a tone when it needs my attention helps.</p>
<h2 id="those-hoofbeats-are-centaurs">Those Hoofbeats Are Centaurs</h2>
<p>The &quot;centaur analogy&quot; is one of the more positive images for working with AI. AI makes you like a centaur; you're faster and stronger but still have all the abilities you have now. If something turned you into a centaur it would replace your human legs with a horse's four legs (and...um...that whole extra torso) so that you can gallop and leap over streams and fences instead of just boring old walking. With a little practice you can shoot arrows behind you over your back (...second back). AI supplements your ability to do whatever AI can help with, but you're still the human-on-top, and are still in charge. This analogy comes from Garry Kasparov. Back in 1997 Deep Blue beat Kasparov in a fair chess match. In 1998 Garry Kasparov bounced back and invented a new game - Centaur Chess - where chess masters partnered with machines to play chess at a new level of dazzling skill. AI advocates and satirists have extended that analogy to the new generation of LLMs.</p>
<p>(Murray Campbell, one of Deep Blue's engineers, later pointed out that the illogical sacrifice Deep Blue used to beat Kasparov the year before to inspire Centaur Chess was &quot;neither human interference nor artificial ingenuity. It was just a glitch.&quot; A bug begat the six-limbed centaur! - <a href="https://www.sciencehistory.org/stories/magazine/thinking-machines-the-search-for-artificial-intelligence/">Science History Institute</a>)</p>
<p>I've spent about 10 months now trying out my centaur legs. Work bought us a license for Anthropic's Claude Code, and I've purchased their $20/mo plan for my hobby work. It's time I write up what I've learned.</p>
<h2 id="a-centaurs-uneven-pace">A Centaur's Uneven Pace</h2>
<p>Using LLMs has changed the pacing of my work for the first time since automatic memory management made it so steady - about thirty years ago. Working with LLMs impacts the pace at the 3-second time-scale all the way to planning my weeks. I'm working faster, but my pace is uneven and harder to predict. This blog is mostly about the finest scale. I'll talk about the longer loops in future blogs.</p>
<h2 id="my-pedestrian-dev-loop">My Pedestrian Dev Loop</h2>
<p>At the finest scale I write a little code, then check that everything is fine. That's the core software developer activity. The finest scale loop is me typing while my code editor checks what I just typed for obvious mistakes. I'm writing Scala code in Intellij; the editor catches most of my mistakes at about the same speed as my visual focus, about 1-3 seconds. The second-finest is when I've made some small change complete enough to compile, assemble into a working system, and test. Depending on the project, that takes between ten seconds (for a small, isolated project where I've optimized the build) to five minutes (for a big, warty legacy project where I haven't tightened the types so it relies on slow, automated tests). I look at results from the previous step, think for a bit, write some test code, write some production code, compile and test, repeat until the next meeting.</p>
<p>Watching me work has to be the least cinematic experience ever: reclining suburbanite in cargo shorts and a tee shirt stops typing, stares menacingly out the window for some moments, smiles. His expression then relaxes as he types again. After four hours he eats lunch, then does more of the same. Maybe the director will ask the lighting designer to do something interesting for the montage to close the scene with a good sunset. I like that it is meditative.</p>
<h2 id="walk-trot-walk-gallop-walk-jump-walk">Walk-Trot-Walk-Gallop-Walk-Jump-Walk</h2>
<p>The pace of working with Claude Code is less even and less centered on my simple loop. Claude Code and I editing the same files at the same time results in us paving over each other's changes, so using Claude Code is turn-based: I give Claude a directive paragraph in a prompt, Claude ingests my request, uploads supporting background information from my laptop to the server at Anthropic, does whatever blackbox processing it does there, downloads changes from Anthropic, and applies the changes to my source code files. Then it's my turn to review the changes, decide if more are needed, and figure out the next directive. The rhythm is like chess without a clock. Claude may take 10 seconds or 40 minutes. Big, broad-stroke work predictably takes longer than something simple. (Claude Code tends not to ask for clarification; it'll just guess and keep going.) However, sometimes what seems like a simple ask will take a surprisingly long time.</p>
<p>I do other things while I wait: I have three copies of the source code so I can work on multiple unrelated tasks. I attend to the &quot;non-software&quot; details of my job. If I'm building some personal project instead of work I'll sometimes switch over to household chores or irritating my teenagers. I also have this amazing laptop with an internet full of distractions. Then Claude needs my permission or guidance or review. Claude stops and waits. I'm reading about destructive archeology practices from the 1900s, or putting together slow bread or blackberry crumble recipes, or discussing Pokemon taxonomy with some kid. Claude's prompt stays open, ignored, forgotten.</p>
<h2 id="boink">Boink!</h2>
<p>That won't do at all. I figured out these settings to get Claude to go &quot;boink&quot; when it needs my attention.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  ...
  <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    ...
    <span class="token property">"Stop"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"afplay /System/Library/Sounds/Glass.aiff &amp;"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"Notification"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">"permission_prompt"</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"afplay /System/Library/Sounds/Funk.aiff &amp;"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"PreCompact"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"afplay /System/Library/Sounds/Sosumi.aiff &amp;"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"StopFailure"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"afplay /System/Library/Sounds/Basso.aiff &amp;"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  ...
<span class="token punctuation">}</span></code></pre>
<p>If you're on a Mac these afplay commands should work. Other platforms have other options for playing sounds or flashing the screen. Some of those options - like printing the ascii bell character - are likely disabled, possibly at several levels. (Try and get Claude to play an ascii bell tone if you're mad at it.) Cut-and-paste this into a Claude Code prompt, and it will gleefully do the work for you.</p>
<p>That lets me work on separate coding tasks simultaneously, plus write or review a document full of directives for the AI for next turn. It is not like working with a peer or an intern. It's more like being GM for an on-line multiplayer text game where I'm driving the plot forward for separated groups of impatient but chipper players. I'm working in parallel. It's a lot of activity, a lot of context switches, and a lot of boinks. I get more done in less time in code, and in the kitchen. It makes for a slightly more exciting scene because every so often the computer goes &quot;Boink!&quot;</p>
<p>However, it is not meditative. Sometimes I'll set aside Claude Code and  write some example Scala structures just the way I want, or write text directives with nothing else running to get back to that relaxed, focused state.</p>
<hr>
<p><strong>Reading:</strong> Cory Doctorow's <a href="https://craphound.com/category/littlebrother/"><em>Little Brother</em></a>. Fun start. Great pace.</p>
<p><strong>Listening:</strong> <a href="https://shows.acast.com/the-mistholme-museum-of-mystery-morbidity-and-mortality">The Mistholme Museum of Mystery, Morbidity, and Mortality</a>. Good vignettes for driving...and it seems there's a larger plot after all.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Bounding Complexity in Scala Projects</title>
      <link>https://blog.walend.net/2024/04/bounding-complexity-in-scala-projects/</link>
      <guid isPermaLink="true">https://blog.walend.net/2024/04/bounding-complexity-in-scala-projects/</guid>
      <pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <category>Scala</category>
      <category>Scala-Basics</category>
      <description>Li Haoyi&#39;s Principle of Least Power, applied to three of my own Scala projects. Scala works best as your own little language, kept deliberately small.</description>
      <content:encoded><![CDATA[<p>Li Haoyi wrote a masterful blog entry <a href="https://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html">Strategic Scala Style: Principle of Least Power</a>. It is a reaction to Tim Berners-Lee's personal notes on W3, <a href="https://www.w3.org/DesignIssues/Principles.html">Principles of Design</a> . Berners-Lee's section on &quot;The Principle of Least Power&quot; opens with:</p>
<blockquote>
<p>The choice of language is a common design choice. The low power end of the scale is typically simpler to design, implement, and use, but the high power end of the scale has all the attraction of being an open-ended hook into which anything can be placed: a door to uses bounded only by the imagination of the programmer.</p>
</blockquote>
<blockquote>
<p>Computer Science in the 1960s to 80s spent a lot of effort making languages which were as powerful as possible. Nowadays [1998?] we have to appreciate the reasons for picking not the most powerful solution but the least powerful.</p>
</blockquote>
<p>That doesn't bode well for Scala - one of the most powerful languages in use. Scala has a Turing-complete compile-time type system. In this blog entry I hope to reconcile these grand architecture-level ideas by bounding how much of Scala's complexity to allow in a project.</p>
<p>First, allow me to defuse Berners-Lee's concerns. The preamble to the above quote is:</p>
<blockquote>
<p>In choosing computer languages, there are classes of program which range from the plainly descriptive (such as Dublin Core metadata, or the content of most databases, or HTML) though logical languages of limited power (such as access control lists, or conneg content negotiation) which include limited propositional logic, though declarative languages which verge on the Turing Complete (Postscript is, but PDF isn't, I am told) through those which are in fact Turing Complete though one is led not to use them that way (XSLT, SQL) to those which are unashamedly procedural (Java, C).</p>
</blockquote>
<p>He goes on to say:</p>
<blockquote>
<p>The reason for this is that the less powerful the language, the more you can do with the data stored in that language. If you write it in a simple declarative from, anyone can write a program to analyze it in many ways. The Semantic Web is an attempt, largely, to map large quantities of existing data onto a common language so that the data can be analyzed in ways never dreamed of by its creators. If, for example, a web page with weather data has RDF describing that data, a user can retrieve it as a table, perhaps average it, plot it, deduce things from it in combination with other information. At the other end of the scale is the weather information portrayed by the cunning Java applet [remember 1998]. While this might allow a very cool user interface, it cannot be analyzed at all. The search engine finding the page will have no idea of what the data is or what it is about. This the only way to find out what a Java applet means is to set it running in front of a person.</p>
</blockquote>
<p>These examples are data structure examples, specifically decoupling data from code. During the 1990s book layout evolved into data structure representation, leaving a fossil record from SGML to HTML to XML. It seems to have resolved with JSON from JavaScript in the 2000s. This was a big deal at the time, and Dr. Berners-Lee played a fantastic lead part. However, you could narrow the word &quot;language&quot; to &quot;data serialization structure&quot; and have an argument that better-matches the examples.</p>
<p>Anyone proposing to use the in-memory bytes that make a Scala case class outside of memory might be demonstrating <a href="https://www.google.com/search?client=firefox-b-1-e&amp;q=futurama+i+c+wiener#fpstate=ive&amp;vld=cid:e0f6d940,vid:tIBmNOJZdWA,st:0">successful cryogenic revival</a> from the early Clinton era. It would stand out as an absolutely terrible proposal given all the <a href="https://index.scala-lang.org/search?sort=stars&amp;q=json&amp;page=1">options available for JSON serialization in Scala</a>: circe, upickle, play-json, zio-json, json-lenses, json4s, akka-http-json, tethys, nestorpersist, rojoma-json, sbt-json, jawn, argonaught, dijon, scalajson, scalajack, ...</p>
<p>I'll get back to language and complexity in a bit. This huge, incomplete list of JSON libraries highlights a related problem.</p>
<h1 id="abundance-in-the-ecosystem">Abundance in the Ecosystem</h1>
<p>Scala started life piggybacking on the Java Virtual Machine's enormously successful ecosystem. Scala has always had access to an abundant ecosystem of Java libraries. Because the Scala language is so well structured we tend to pick and choose libraries instead of locking ourselves into frameworks. (Contrast with Ruby on Rails.) As a community we are very comfortable creating new solutions - new libraries - when old solutions don't match the problems of the day. Mostly that's for the better, but it does lead to a fractured community and complexity from the viable number of choices. Martin Odersky complained that we were not &quot;Scala programs&quot; but were &quot;Cats programmers, or Akka programmers, or Spark programmers.&quot;</p>
<h1 id="and-abundant-language-features">...and Abundant Language Features</h1>
<p>The Scala language is actually quite small, with remarkably few caveats. However, many language-like features come in via the standard library. Scala is multi-paradigm; I've seen it work well for object-oriented programming, functional programming, declarative programming, procedural-style programming and even aspect-oriented programming. Further, in Scala it is very natural to make your own new control structures to fit your project's needs.</p>
<p>One common complaint is that Scala has a steep learning curve. I don't think that's true; I have taught 4th-graders how to write some useful Scala. It is easy to get started. The problem is not the steepness; the problem is the height of the curve.</p>
<p>When I ask for help from a typical Scala Users' Group often the answer is &quot;Go read and understand [something I never even knew was there].&quot; I value learning new things, but often want to learn separate from getting the job done.</p>
<blockquote>
<p>&quot;Experience is what you get when you didn't get what you wanted.&quot; - Randy Pausch</p>
</blockquote>
<p>Further, the Scala language often has multiple ways to get the same result. I think that leads directly to Li Haoyi's <a href="https://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html">Principle of Least Power</a> examples. Smart academics do amazing things with the language, but maybe that's not the right choice for your project. To get non-academic work done in an ecosystem this rich you need to set some boundaries for your project. You can control the height your developers need to climb by deciding to use simpler and fewer parts of Scala.</p>
<h1 id="audience">Audience</h1>
<p>I don't agree with Li Haoyi that &quot;Complexity is your enemy.&quot; A project's ability to handle complexity is more like a scarce resource. Scala lets you treat complexity like items on a menu where other languages, frameworks, and ecosystems offer a fixed-price of complexity. Academics can afford an abundance of complexity. The rest of us, <a href="https://www.google.com/search?client=firefox-b-1-e&amp;sca_esv=568821e4bd74bee9&amp;sca_upv=1&amp;sxsrf=ACQVn0915nVZxnE9GxYNe--dLEfZ9tuPrQ:1714501579949&amp;q=la+story+patrick+stewart&amp;tbm=vid&amp;source=lnms&amp;prmd=ivnsbmtz&amp;sa=X&amp;ved=2ahUKEwi6zY6NyOqFAxX1ElkFHRRLApIQ0pQJegQIChAB&amp;biw=1290&amp;bih=913&amp;dpr=2#fpstate=ive&amp;vld=cid:ad5b044b,vid:C1IRqqp8vHw,st:0">not so much</a>.</p>
<p>Think about who is going read and write your code to get some idea of what budget you have for complexity, and who might be using the software. You need to set expectations so that your audience is not surprised when they need to learn new skills to contribute.</p>
<p>I think the most important question to answer is &quot;What do you expect people to do with the systems you create?&quot; The people might be users, system admins, support crew, or future developers; there will be different audiences for different roles. They'll bring different levels of skill and expectations.</p>
<h1 id="three-examples">Three Examples:</h1>
<h2 id="shrine"><a href="https://open.catalyst.harvard.edu/stash/projects/SHRINE/repos/shrine/browse">SHRINE</a></h2>
<p>SHRINE allows a researcher at any hospital in a network to query patient records at all hospitals in that network with the same query – without violating HIPAA. The audience includes researchers, local and network admins, and future software developers. (I just finished my work on SHRINE, which involved a lot of writing to archive it for future developers. I've been thinking about this issue a lot lately.)</p>
<p>SHRINE's users are pragmatic medical researchers; they are brilliant people but not computer scientists. The researchers drag-and-drop term labels in boxes to form logical queries for patients they hope to study. The researchers are using a visual domain-specific query language; behind the curtain it is all JSON.</p>
<p>The local and network admins mostly use Unix skills, <a href="https://github.com/lightbend/config">HOCON via Typelevel Config</a>, and peek inside databases and logs to bracket and understand problems. The admins are very capable with Unix and python scripts, but most of their interaction with SHRINE is via a single HOCON configuration file. It is extremely unusual to see any of them use any HOCON beyond the basic key/value pairs. (In the narrow realm of setting up SHRINE they are safe from Dr. Berners-Lee's fear of attraction to powerful language features.)</p>
<p>I left future SHRINE developers with a wiki entry opening with:</p>
<blockquote>
<p>SHRINE uses Scala 2.13.x for all of its back-end code. The Scala code style is functional and highly monadic. It features shallow object-oriented components - often comprised of shared parts - to separate concerns. This lets the code explain the details itself. We build it with Maven - the easiest system for our operations team to support. SHRINE uses http4s for its web API, cats effects and fs2 for concurrency, CQRS via slick for storing and retrieving state. SHRINE sends commands between nodes using MOM (AWS SQS, Kafka, or a home-grown REST API), circe for encoding JSON, i2b2 as a source of patient data, and Scala's xml library to create and read i2b2's xml. SHRINE stores very little state outside of stack references.</p>
</blockquote>
<p>That opening lists out the core technologies and the minimum skill set to bring. A developer familiar with http4s, cats effects, and distributed programming would likely be able to contribute as soon as they understand the problem SHRINE solves. I would expect a generally capable Scala developer to &quot;go read about&quot; all of those technologies and get some level of how SHRINE uses them before attempting to make changes to SHRINE's code base. It's a punch-list like you would find in a job description.</p>
<p>In 2008 SHRINE began as a &quot;Scala as a better Java&quot; project that used Jakarta and Scala's in-line XML capability to imitate and distribute a single-hospital query system's web API. We were able to grow SHRINE from those initial decisions while keeping the whole works compatible release-to-release (mostly). SHRINE's transformation is a remarkable demonstration of the <a href="https://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html#dont-fear-refactoring">power of refactoring</a> in Scala Li Haoyi finds so compelling.</p>
<h2 id="ev3dev-lang-scala"><a href="https://github.com/dwalend/ev3dev-lang-scala">ev3dev-lang-scala</a></h2>
<p>ev3dev-lang-scala is a library and toolkit for programming Lego Ev3 robots using Scala. Most programmers using the library are kids ages 9 to 13, mostly programming robots for <a href="https://www.firstinspires.org/robotics/fll/game-and-season">FIRST Lego League</a>. I've created a library that gives them a subset of the Scratch-like tool Lego provides. To keep things fair the library does not give them anything more than what Lego's base-level blocks provide, but they do have access to all of Scala. I try to get them to use some object-oriented containment to keep it easy to explain. Individual kids do not value that in their own work but complain when another kid makes a mess of it, especially while making presentations days before an FLL tournament. Most code the kids write is very procedural, like this method to drive the robot (backwards) to a &quot;museum&quot; objective:</p>
<pre class="language-scala"><code class="language-scala">  <span class="token keyword">private</span> <span class="token keyword">def</span> startToMuseum<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Unit</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
    Robot<span class="token punctuation">.</span>moveStraightBackward<span class="token punctuation">(</span><span class="token number">635.</span>millimeters<span class="token punctuation">)</span>
    Robot<span class="token punctuation">.</span>leftRotation<span class="token punctuation">(</span><span class="token number">135.d</span>egrees<span class="token punctuation">)</span>
    Robot<span class="token punctuation">.</span>moveStraightBackward<span class="token punctuation">(</span><span class="token number">100.</span>millimeters<span class="token punctuation">)</span>
    Robot<span class="token punctuation">.</span>leftRotation<span class="token punctuation">(</span><span class="token number">100.d</span>egrees<span class="token punctuation">)</span>
    Robot<span class="token punctuation">.</span>moveStraightBackward<span class="token punctuation">(</span><span class="token number">570.</span>millimeters<span class="token punctuation">)</span>
    Robot<span class="token punctuation">.</span>rightRotation<span class="token punctuation">(</span><span class="token number">135.d</span>egrees<span class="token punctuation">)</span>
    Robot<span class="token punctuation">.</span>rightRotation<span class="token punctuation">(</span><span class="token number">180.d</span>egrees<span class="token punctuation">)</span>
  <span class="token punctuation">}</span></code></pre>
<p>The kids surprised me when they used a recursive loop to use feedback from a gyroscope to make precise turns:</p>
<pre class="language-scala"><code class="language-scala">  <span class="token annotation punctuation">@tailrec</span>
  <span class="token keyword">def</span> rightRotation<span class="token punctuation">(</span>goalHeading<span class="token operator">:</span>Degrees<span class="token punctuation">)</span><span class="token operator">:</span><span class="token builtin">Unit</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token keyword">val</span> heading<span class="token operator">:</span> Degrees <span class="token operator">=</span> Gyroscope<span class="token punctuation">.</span>readHeading<span class="token punctuation">(</span>SensorPort<span class="token punctuation">.</span>One<span class="token punctuation">)</span>
    <span class="token keyword">val</span> toGo<span class="token operator">:</span> Degrees <span class="token operator">=</span> goalHeading <span class="token operator">-</span> heading
    <span class="token keyword">val</span> speed<span class="token operator">:</span> DegreesPerSecond <span class="token operator">=</span> <span class="token punctuation">(</span>Robot<span class="token punctuation">.</span>speed<span class="token punctuation">.</span>v <span class="token operator">*</span> <span class="token punctuation">(</span>toGo<span class="token punctuation">.</span>v<span class="token operator">/</span><span class="token number">90</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>degreesPerSecond

    Log<span class="token punctuation">.</span>log<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token id function">s</span><span class="token string">"heading is </span><span class="token interpolation"><span class="token punctuation">$</span><span class="token expression">heading</span></span><span class="token string">, speed is </span><span class="token interpolation"><span class="token punctuation">$</span><span class="token expression">speed</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>goalHeading <span class="token operator">></span> heading<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      Movement<span class="token punctuation">.</span>startMoving<span class="token punctuation">(</span>speed<span class="token punctuation">,</span><span class="token operator">-</span>speed<span class="token punctuation">)</span>
      rightRotation<span class="token punctuation">(</span>goalHeading<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      Movement<span class="token punctuation">.</span>stop<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<p>To trim back their cut-paste tendencies I want to show them higher-order functions this year. A general feedback loop might be the thing, but they resist refactoring. &quot;It works fine. Why change it?&quot; They do not get it.</p>
<p>The other audience is library developers - just me so far. To make this thing work I had to learn the basics of interfacing with the <a href="https://www.ev3dev.org/">ev3dev OS</a> (a variant Debian Linux!) and how to use that interface efficiently from inside the JVM. To get the control loops running at ~200 Hz after hot-spot warm-up the core uses Java NIO calls to read and write unix streams, very much &quot;Scala as a better Java&quot; in style:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">case</span> <span class="token keyword">class</span> ChannelRewriter<span class="token punctuation">(</span>path<span class="token operator">:</span> Path<span class="token punctuation">,</span>bufferLength<span class="token operator">:</span><span class="token builtin">Int</span> <span class="token operator">=</span> <span class="token number">32</span><span class="token punctuation">)</span> <span class="token keyword">extends</span> AutoCloseable <span class="token punctuation">{</span>

  <span class="token keyword">private</span> <span class="token keyword">val</span> channel <span class="token operator">=</span> FileChannel<span class="token punctuation">.</span><span class="token keyword">open</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span>StandardOpenOption<span class="token punctuation">.</span>WRITE<span class="token punctuation">)</span>
  <span class="token keyword">private</span> <span class="token keyword">val</span> byteBuffer <span class="token operator">=</span> ByteBuffer<span class="token punctuation">.</span>allocate<span class="token punctuation">(</span>bufferLength<span class="token punctuation">)</span>

  <span class="token keyword">def</span> writeString<span class="token punctuation">(</span>string<span class="token operator">:</span> <span class="token builtin">String</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token builtin">Unit</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>synchronized<span class="token punctuation">{</span>
    byteBuffer<span class="token punctuation">.</span>clear<span class="token punctuation">(</span><span class="token punctuation">)</span>
    byteBuffer<span class="token punctuation">.</span>put<span class="token punctuation">(</span>string<span class="token punctuation">.</span>getBytes <span class="token punctuation">(</span>StandardCharsets<span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span> <span class="token punctuation">)</span>
    byteBuffer<span class="token punctuation">.</span>flip<span class="token punctuation">(</span><span class="token punctuation">)</span>
    channel<span class="token punctuation">.</span>truncate<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
    channel<span class="token punctuation">.</span>write<span class="token punctuation">(</span>byteBuffer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
    channel<span class="token punctuation">.</span>force<span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">def</span> writeAsciiInt<span class="token punctuation">(</span>i<span class="token operator">:</span> <span class="token builtin">Int</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token builtin">Unit</span> <span class="token operator">=</span> writeString<span class="token punctuation">(</span>Integer<span class="token punctuation">.</span>toString<span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token keyword">def</span> close<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token builtin">Unit</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>synchronized<span class="token punctuation">{</span>
    channel<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>I don't expect the kids to work at this level, but a beginner Scala developer with a Unix background and familiarity with Java's NIO API should be able to contribute. On their best days the kids will use the IDE to follow calls down from their own code into the library to see how things work.</p>
<p>You'll notice the kids' code refers to measured units like <code>.millimeters</code>, <code>.seconds</code>, and <code>.degrees</code> - Scala value classes. I have figured out how to program the Scala3 type system to understand measured units in arithmetic - some number of <code>degrees</code> divided by some number of <code>seconds</code> is <code>degrees/seconds</code>. I'm of two minds deciding if it is the right thing to do. It would save the kids having to dig out the values via <code>.v</code> to do their arithmetic, then rewrap up the result to have the correct type (all cooked out in the compiler via Scala's value class feature). However, it would add type-level arithmetic programming to the inner workings of the library code - a leap up the learning curve from &quot;Scala as a better Java.&quot; I don't yet know what the right decision is.</p>
<p>Scala lets me put that decision off. The language supports the complex types.</p>
<h2 id="disentangle"><a href="https://github.com/dwalend/Disentangle">Disentangle</a></h2>
<p>Disentangle is a library of graph algorithms I use mostly for my own entertainment. (I did use the library at ActivateNetworks for analyzing social networks for marketing.) I implemented graph minimization algorithms - like Dijkstra's shortest path algorithm - with general-purpose semirings. The same algorithm code can find things like least-probable paths instead. To use an algorithm a developer needs to understand how to use Scala's tuple structures and collections library - entry-level Scala skills:</p>
<pre class="language-scala"><code class="language-scala">  <span class="token comment">/**
   * Edges are just a Seq of Tuple3[Node,Node,Edge]
   */</span>
  <span class="token keyword">lazy</span> <span class="token keyword">val</span> edges<span class="token operator">:</span> Seq<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> Seq<span class="token punctuation">(</span>
                                                  <span class="token punctuation">(</span><span class="token string">"A"</span><span class="token punctuation">,</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"ab"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"bc"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"D"</span><span class="token punctuation">,</span><span class="token string">"cd"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"D"</span><span class="token punctuation">,</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"de"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"F"</span><span class="token punctuation">,</span><span class="token string">"ef"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"eb"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"H"</span><span class="token punctuation">,</span><span class="token string">"eh"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                  <span class="token punctuation">(</span><span class="token string">"H"</span><span class="token punctuation">,</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"hc"</span><span class="token punctuation">)</span>
                                                <span class="token punctuation">)</span>

  <span class="token comment">/**
   * Generate all the shortest paths in the graph
   */</span>
  <span class="token keyword">lazy</span> <span class="token keyword">val</span> simpleShortPathLabels<span class="token operator">:</span> Seq<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">,</span> Option<span class="token punctuation">[</span>FirstStepsTrait<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">Int</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> Dijkstra<span class="token punctuation">.</span>allPairsShortestPaths<span class="token punctuation">(</span>edges<span class="token punctuation">)</span></code></pre>
<p>I use Scala's generics to keep the types lined up right for different semirings, but otherwise the code is using shallow object-oriented ideas to keep different concerns separated. Scala's solid handling of generics for Disentangle is what first drew me into Scala. Here's a semiring for finding most-probable paths:</p>
<pre class="language-scala"><code class="language-scala">  <span class="token keyword">object</span> MostProbableSemiring <span class="token keyword">extends</span> Semiring <span class="token punctuation">{</span>

    <span class="token keyword">val</span> I <span class="token operator">=</span> <span class="token number">1.0</span>
    <span class="token keyword">val</span> O <span class="token operator">=</span> <span class="token number">0.0</span>

    <span class="token keyword">def</span> inDomain<span class="token punctuation">(</span>label<span class="token operator">:</span> Label<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Boolean</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
      I <span class="token operator">>=</span> label <span class="token operator">&amp;&amp;</span> label <span class="token operator">></span> O
    <span class="token punctuation">}</span>

    <span class="token keyword">def</span> summary<span class="token punctuation">(</span>fromThroughToLabel<span class="token operator">:</span>Label<span class="token punctuation">,</span> currentLabel<span class="token operator">:</span>Label<span class="token punctuation">)</span><span class="token operator">:</span>Label <span class="token operator">=</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span><span class="token punctuation">(</span>fromThroughToLabel <span class="token operator">></span> currentLabel<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        fromThroughToLabel
      <span class="token punctuation">}</span>
      <span class="token keyword">else</span> currentLabel
    <span class="token punctuation">}</span>

    <span class="token keyword">def</span> extend<span class="token punctuation">(</span>fromThroughLabel<span class="token operator">:</span>Label<span class="token punctuation">,</span>throughToLabel<span class="token operator">:</span>Label<span class="token punctuation">)</span><span class="token operator">:</span>Label <span class="token operator">=</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>fromThroughLabel <span class="token operator">==</span> O<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>throughToLabel <span class="token operator">==</span> O<span class="token punctuation">)</span><span class="token punctuation">)</span> O
      <span class="token keyword">else</span> <span class="token punctuation">{</span>
        fromThroughLabel <span class="token operator">*</span> throughToLabel
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<p>The core idea behind the library is to write algorithm code that looks identical to the pseudocode in fat algorithm books like <a href="https://www.amazon.com/Introduction-Algorithms-3rd-MIT-Press/dp/0262033844">CLRS</a>. Here's the Floyd-Warshall algorithm demonstrating &quot;Scala as a better <s>Java</s> Fortran&quot; :</p>
<pre class="language-scala"><code class="language-scala">  <span class="token comment">/**
   * O(n^3)
   */</span>
  <span class="token keyword">def</span> floydWarshall<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>Label<span class="token punctuation">,</span>Key<span class="token punctuation">]</span><span class="token punctuation">(</span>labelDigraph<span class="token operator">:</span>MatrixLabelDigraph<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>Label<span class="token punctuation">]</span><span class="token punctuation">,</span>support<span class="token operator">:</span>SemiringSupport<span class="token punctuation">[</span>Label<span class="token punctuation">,</span>Key<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">:</span>IndexedLabelDigraph<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>Label<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token keyword">val</span> innerNodes <span class="token operator">=</span> labelDigraph<span class="token punctuation">.</span>innerNodes
    <span class="token keyword">for</span> <span class="token punctuation">(</span>k <span class="token keyword">&lt;-</span> innerNodes<span class="token punctuation">;</span> i <span class="token keyword">&lt;-</span> innerNodes<span class="token punctuation">;</span> j <span class="token keyword">&lt;-</span> innerNodes<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">val</span> summaryLabel <span class="token operator">=</span> relax<span class="token punctuation">(</span>labelDigraph<span class="token punctuation">,</span>support<span class="token punctuation">.</span>semiring<span class="token punctuation">)</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span>k<span class="token punctuation">,</span>j<span class="token punctuation">)</span>
      labelDigraph<span class="token punctuation">.</span>upsertEdge<span class="token punctuation">(</span>i<span class="token punctuation">,</span>j<span class="token punctuation">,</span>summaryLabel<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    labelDigraph
  <span class="token punctuation">}</span></code></pre>
<p>There's this split between how different audiences will interact with the code. Someone could just use this library in a project with an entry-level understanding of Scala. To add new algorithms you need Scala generics to keep the code type-safe.</p>
<h1 id="in-contrast-my-early-career">In Contrast: My Early Career</h1>
<p>My first job out of school involved converting Matlab code and Excel spreadsheets into Fortran (... and postscript). The third and fifth projects were converting Matlab into Objective C . The seventh project was an attempt to convert a system in C to Java. (It failed.) My eighth through twelfth projects were converting Matlab into Java. My second Scala project was translating R code into Scala.</p>
<p>I did take a job at MathWorks after all that Matlab translation. Jack Little, founder of MathWorks, pointed out that, &quot;You can write a lot of really terrible Matlab code really fast. That's one of its greatest strengths.&quot; I get that as a marketing plan for MathWorks, an action plan for a researcher, and a business plan for a start-up. All that recoding paid my student loans, rent, and kept me in food for my early career, but was somewhat unsatisfying. I did observe that once a project chose a production ecosystem then that choice was for the life of the project. If the language or ecosystem didn't provide something that the project needed then that venture failed. Big rewrites were too expensive.</p>
<h1 id="scala-is-best-as-your-little-language">Scala is Best as Your Little Language</h1>
<p>Scala libraries regularly evolve into domain-specific languages as the authors get more understanding about how to write concise, clear code. The Scala community takes a lot of pride in that. Here's some SHRINE code that uses <a href="https://http4s.org/v1/docs/dsl.html">http4s</a>' end-point DSL:</p>
<pre class="language-scala"><code class="language-scala">    <span class="token keyword">case</span> request @ POST <span class="token operator">-></span> Root <span class="token operator">/</span> <span class="token string">"startQuery"</span> as user <span class="token keyword">=></span> startQuery<span class="token punctuation">(</span>request<span class="token punctuation">,</span>user<span class="token punctuation">)</span>

    <span class="token keyword">case</span> request @ POST <span class="token operator">-></span> Root <span class="token operator">/</span> <span class="token string">"changeQueryNameAndNotes"</span> <span class="token operator">/</span> LongVar<span class="token punctuation">(</span>queryId<span class="token punctuation">)</span> as user <span class="token keyword">=></span> changeQueryNameAndNotes<span class="token punctuation">(</span>queryId<span class="token punctuation">,</span> request<span class="token punctuation">,</span> user<span class="token punctuation">)</span>

    <span class="token keyword">case</span> _ @ GET <span class="token operator">-></span> Root <span class="token operator">/</span> <span class="token string">"query"</span> <span class="token operator">/</span> LongVar<span class="token punctuation">(</span>queryId<span class="token punctuation">)</span> as user <span class="token keyword">=></span> getQuery<span class="token punctuation">(</span>queryId<span class="token punctuation">,</span> user<span class="token punctuation">)</span></code></pre>
<p>In Scala the line between what's &quot;just a library&quot; vs &quot;what is a DSL&quot; is pretty blurry. We bring these into code via <code>import org.http4s.dsl...</code> but pieces we're importing are masterfully-designed <code>unapply</code> methods to be used in <code>case</code> statements. There's no new parser, no changes to a compiler, no magic plugins, not even annotations. It just lets our team write concise, clear Scala code.</p>
<p>By choosing which parts of Scala to use and which to leave out we can define the right little language for each project. Changes to these decision have an incremental, bound cost ; if we need to make a different choice in the future we can either let some new kind of complexity in, or refactor to simplify. That's a tremendous benefit. It helps Scala projects live long, healthy lives by letting them adapt to changing needs.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The 20-Minute Limit</title>
      <link>https://blog.walend.net/2024/04/the-20-minute-limit/</link>
      <guid isPermaLink="true">https://blog.walend.net/2024/04/the-20-minute-limit/</guid>
      <pubDate>Tue, 16 Apr 2024 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <category>SDLC</category>
      <description>The first advice I give interns: don&#39;t be stuck more than 20 minutes. Long enough to try it yourself, short enough to keep tempo and ask a good question.</description>
      <content:encoded><![CDATA[<p>The first bit of guidance I give to the interns I hire is, &quot;Don't be stuck for more than 20 minutes.&quot;</p>
<p>&quot;Take 20 minutes to see if you can solve it yourself. After that ask for help. We're all here to get the job done. You aren't alone. We want you to learn to work independently, but we don't expect you to know how to do that right away. Try being independent for 20 minutes, learn from that, then let someone know.&quot;</p>
<p>I try to follow my own advice.</p>
<p>20 minutes of wishing you could find the right thing to read or staring into the void hoping for inspiration is plenty. If you have the right buzzwords to feed into Google then you're most likely to find the right article to read in the first few tries. After that the odds drop off; you don't know the right magic words. I bet the success rate for technical questions follows Planck's curve - maybe better than this solar radiation graph from Wikpedia.</p>
<p><img src="https://blog.walend.net/img/posts/2024-04-16-planck-curve.png" alt="Solar radiation spectrum, showing Planck's curve"></p>
<p>If what you really need is inspiration, taking 20 minutes to summarize what you already know is a good warm-up. If you haven't already thought about the problem and recalled the answer then you are better off either asking for help or setting the problem aside and letting your brain bubble away while you do something else.</p>
<p>Odds are someone you work with knows the right thing for you to read, can tell you something better to search for, or has already thought through some part of the problem you are working on. They can help you. Get their help. Investing 20 minutes is enough to ask a good-quality question to get that help. (Less time is probably not enough to ask the good question.)</p>
<p>I expected the interns to struggle with this advice. I had guessed that students would be used to working independently, following academic rules. It was never a problem for them.</p>
<p>Following this advice was a challenge for more experienced people joining our team, especially when one of them was the team expert on the topic. It's harder to imagine the value of framing the question well, then asking someone less knowledgeable for help, but it works really well. Early in my job at HMS I was the only person working on back-end Scala code. When I was clueless, I felt alone and responsible for finding all the answers. Talking through a problem with our front-end developer, our amazing tester, or just someone interested in the project helped me frame the question better. It often showed me what the real concerns were, and saved me from &quot;<a href="https://web.archive.org/web/20050525082529/http://weblogs.java.net/blog/dwalend/archive/2005/01/sharpening_the.html">shaving the yak</a>.&quot; The Scala community - especially the people who eventually made up the Type Level community - were a huge help getting to concrete answers. (Help from Type Level people almost always starts with, &quot;Oh. See if reading ... helps.&quot; It almost always does, but it takes some investment. In contrast, reading the wrong thing is really frustrating.)</p>
<p>I found that talking through my puzzles with an intern was magic. We usually wouldn't come up with a solution right away, but explaining got things fizzing in our heads. I would often make the inspirational connection while I was concentrating on something completely different, like niggling with some other part of the code base, chasing the kids in the park or cooking dinner. It was like my non-euclidean geometry professors from way back warned us: &quot;Go ahead and learn everything about the problem that you can, but don't expect to get anywhere just by applying work to these puzzles. Keep a notepad on your nightstand. You are going to wake up in the middle of the night with the proof in your head, and you must write it down before you go back to sleep. It'll get better with practice, but it will never seem natural.&quot;</p>
<p>One of the deeper things in the Toyota Way is that the advice comes in complementary pairs. I think this 20-minute limit pairs well with the first-day plan. It's a small piece of &quot;how-to&quot; to match with the first-day plan's list of &quot;what.&quot; When someone is starting a new job then the 20-minute limit sets an expectation for how to solve the problem without giving up the tempo, and gives the new employee permission to interrupt.</p>
]]></content:encoded>
    </item>
    <item>
      <title>CQRS in a Relational Database via Slick</title>
      <link>https://blog.walend.net/2024/04/cqrs-in-a-relational-database-via-slick/</link>
      <guid isPermaLink="true">https://blog.walend.net/2024/04/cqrs-in-a-relational-database-via-slick/</guid>
      <pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <category>Scala</category>
      <category>Slick</category>
      <category>CQRS</category>
      <category>RDBMS</category>
      <category>DynamoDB</category>
      <category>CouchDB</category>
      <category>message queue</category>
      <description>CQRS suits systems where inbound data is a stream of events but something needs a coherent view of state. How we built one on Slick and a relational database.</description>
      <content:encoded><![CDATA[<p>CQRS - Command and Query Result Segregation - is a useful tool for systems where the inbound data is a stream of events that behave like telemetry, and parts of the system need some coherent, more complex view of state. With CQRS the system records the events in a list as they flow in. Later, when the system needs a coherent understanding of state, it examines the events and assembles a self-consistent structure. &quot;Command Responsibility&quot; comprises the mechanics to record the events quickly and with minimal blocking - especially minimal locking. &quot;Query Responsibility&quot; absorbs the complexity and cost of assembling a coherent state to meet the reader's needs.</p>
<p><img src="https://blog.walend.net/img/posts/2024-04-12-cqrs-diagram.png" alt="Events flow into an event queue and event storage under Command Responsibility; state storage answers queries under Query Responsibility"></p>
<p>This arrangement removes the bottleneck of processing the data as it comes in by moving the work of refining the data to some time before it will be used. If the data is used in multiple ways then each use can have its own specialized refinement to match that use's queries.</p>
<p>In distributed system terms CQRS defines the first, most time-dependent map on the event stream to &quot;just store the events,&quot; delays and separates that from a complex reduce of &quot;convert the events to something useful,&quot; then enables efficient queries of the structure that best matches the end-use.</p>
<p>The best candidate systems for CQRS are systems where events arrive out-of-order; that's pretty much any system with distributed, changing state. It also includes every system that uses message-oriented middleware; even with best-effort configurations to keep messages in-order they can still arrive out-of-order. Within a single computer: parallel threads can execute in strange orders, &quot;happens before&quot; rules are softer than we might wish, and computer clocks are notoriously bad. Sometimes a program running on a single computer can benefit from CQRS.</p>
<p>Systems where updates come in rapidly benefit from the efficient processing of writes in the &quot;Command Responsibility.&quot; The &quot;Command Responsibility&quot; writing of updates is relatively straight-forward to replicate across threads and even distributed servers, so it scales up easily with the volume of data flowing in. Systems that process and use the data for different purposes benefit from the separation of &quot;Query Responsibility.&quot; Each can have its own on-demand processing of the stored events. The stored events naturally provide an audit trail and the ability to replay the events. Replaying the events to debug a distributed system is invaluable, perhaps the most powerful &quot;Query Responsibility&quot; feature.</p>
<p>I'll be pulling examples from my work at HMS Catalyst on SHRINE (the Shared Hospital Research Information Network E) - a system that allows a researcher at any hospital to query for counts of patients with similar characteristics at all the hospitals in the network. The core idea behind SHRINE is that patient records never leave the hospitals; every hospital runs a researcher's query and reports a count of patients to the network.</p>
<p>When I started on SHRINE it used a web API call that fanned out into a layered system of slow and unreliable patient data servers. That initial web API call might take as long as five minutes to finish - with no feedback to the researcher. For usability five minutes is a coffee break; the researcher might not come back. For normal http connections on the internet five minutes is &quot;probably just broken.&quot; SHRINE 2.0+ shows incremental query progress and results as soon as they are available from each hospital. Patient counts for simple queries from the fastest sites show up in a second or two - a usability breakthrough.</p>
<p>SHRINE version 2.0 and onward have a common currency of case classes that represent queries, results, researchers, nodes (usually hospitals), and the SHRINE network itself. (See future blog article after I write it.) The events are changes to these structures.</p>
<p>We started recording events in a simplified &quot;Command Query&quot; style in SHRINE 1.19 because one customer required an audit trail. We expanded it to a CQRS-style local-to-the-user forward cache in SHRINE 1.21 to improve performance. That showed us our system did need to handle distributed state better; SHRINE 1.23 demonstrated the value of incremental updates of the distributed quereis in progress - via message-oriented middleware. In SHRINE 2.0 we adopted CQRS fully and ran it with no significant change to the code for five years. One large network ran SHRINE 3.1 for three years - with no update at all.</p>
<h2 id="do-not-use-cqrs-unless-you-need-it">Do Not Use CQRS Unless You Need It</h2>
<p><em><a href="https://archive.org/details/stnmnst/JPEG/stnmnst0007.jpg">Famous Blue Muppet is taken aback.</a></em><sup><a href="https://blog.walend.net/2024/04/cqrs-in-a-relational-database-via-slick/#a-note-on-famous-blue-muppet">1</a></sup></p>
<p>Li Haoyi's blog entry &quot;Strategic Scala Style: Principle of Least Power&quot; introduces CQRS with &quot;Don't use Event-Sourcing/CQRS unless you know what you're doing.&quot; <a href="https://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html#immutability--mutability">https://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html#immutability--mutability</a> If you haven't read that article - go read it now. It's amazingly good general advice. Then understand why I've got references to Jon Stone's <em>The Monster at the End of This Book</em>, and that what follows is likely not good advice.</p>
<p>If your system's state is immutable - it creates things but never changes them - then you really don't need CQRS. Just record what you create to unpack later.</p>
<p>If state will only change in a slow and sedate fashion on a single thread then you can use something less intense like traditional database transactions. Be aware that database transactions often do not have the ACID properties we wish they did. In a small, slow, sedate, centralized system database transactions will probably be fine. When you put that central database under pressure, with changes coming in concurrently, then expect trouble. With too much locking things will slow down; with too little the system can lose coherency - or even data.</p>
<h2 id="cqrs-creates-a-list-of-events-to-replay">CQRS Creates A List of Events To Replay</h2>
<p>The heart of CQRS is list of events. Some parts of the system emit events. &quot;Command Responsibility&quot; stores events but never changes them. Later &quot;Query Responsibility&quot; replays the events to construct state. Replay the events - in order - to reproduce the state.</p>
<p>You could store the events in a concurrent in-memory structure so long as you aren't concerned with what happens after the process terminates. A simple database table (time stamp and the event structure) can work reasonably well. NoSQL list databases like CouchDB and DynamoDB are even easier to set up than a database; they are possibly overkill for the &quot;Command Responsibility&quot; but work great.</p>
<p>The resulting CQRS system relies on the event time stamps being solid enough for &quot;in order&quot; to work in your system. That pretty well describes what we did for SHRINE 1.21's forward cache; we made a simple database table to record the changes in state, then used the timestamps to generate the states we showed to the researchers. It worked well in a low-traffic network of four hospitals.</p>
<p>Using this event list for a network of four dozen hospitals, many more active researchers, and message-oriented middleware showed us that the timestamps were not good enough to rebuild the state in this busier environment. We had to ruthlessly take advantage of SHRINE's particulars to reassemble the state to resolve conflicts when the time stamps didn't work out. Each new bug we discovered resulted in a new condition to check. The cyclomatic complexity of the logic to reproduce the state started to fold on itself.</p>
<h2 id="sometimes-you-need-cqrs-sometimes-it-wont-be-enough">Sometimes You Need CQRS (Sometimes It Won't Be Enough)</h2>
<p><em><a href="https://archive.org/details/stnmnst/JPEG/stnmnst0009.jpg">Famous Blue Muppet asks you not to read this.</a></em></p>
<p>CQRS is particularly good at making a coherent, self-consistent view available in the chaos that is distributed computing. Observations of time in computing systems are staggeringly horrible.</p>
<p>You might recall <a href="https://www.phys.unsw.edu.au/einsteinlight/jw/module4_pole_paradox.htm">&quot;The Barn Pole Paradox&quot;</a> from relativity physics. Computing is worse.</p>
<p>The resolution of the paradox is to split &quot;Is the pole in the barn?&quot; into two events - &quot;the front of the pole exists barn&quot; and &quot;the end of the pole enters the barn&quot; - then twist them through the Lorentz transform to show that their order can swap based on the observer's frame. (Muppets demonstrating that paradox would be fitting.) At least the geometry of the universe holds the observers to some rules.</p>
<p>Observation in distributed systems - at the bottom of Earth's gravitational well, not moving at significant speeds - don't usually have significant relativistic effects, but they do have:</p>
<p>Discrete time - Different things can happen at the exact same clock time</p>
<p>Processors that run faster than the clock resolution - My laptop clock has an API resolution of one nanosecond, but has processors running at four GHz. About four things should happen in the same tick on each core</p>
<p>Concurrently-running processors - Many things could happen at the same time on different cores. My laptop has 12 cores.</p>
<p>The actual resolution of the operating system's - and JVM's - times are more often on the order of microseconds.</p>
<p>The program reading a clock takes some poorly controlled amount of time.</p>
<p>Computer clocks are temperature-sensitive.</p>
<p>I work mostly on Java virtual machine systems. The JVM's nanosecond clock counts up from an arbitrary point starting when the JVM process starts. It's handy for controlling frame-rate in a video game loop, but would need to be pinned to the operating system's clock for anything off-board.</p>
<p>The JVM's API resolution for the OS' clock is in milliseconds.</p>
<p>The OS's clock resolution might be finer, but in older operating systems may only have accuracy of 30 ms. (One really old OS will sometimes jump backwards 10s of ms!)</p>
<p>The ntp protocol can keep distributed computers' clocks to within about 10 ms on stable LANs, and maybe 100 ms on networks you wished worked better.</p>
<p>ntp can speed up or slow down the clock, especially just after start-up.</p>
<p>The system admin can set the clock to arbitrary values.</p>
<p>A network call across loopback takes at minimum 10s of ms.</p>
<p>Writing a local file takes 10s of ms. Memory buffers makes this highly variable.</p>
<p>http calls across a LAN takes at minimum ~100 ms.</p>
<p>https calls across a WAN takes at minimum 100s of ms.</p>
<p>Reliable message-oriented-middleware (MOM) calls get their reliability by adding more network and file system calls.</p>
<p>Messages in MOM systems may arrive out-of-order for any number of reasons.</p>
<p>MOM also adds queues to the works; messages may sit in queues before they are processed - possibly for days.</p>
<p>MOM's zero-or-more message delivery promise means that a client may receive the same message more than once.</p>
<p>If your system is about changing state across distributed computers then you need some way to build a reliable system around all of that. CQRS is a good starting point, but may not be enough.</p>
<h2 id="the-art-of-compromise-cqrs-but-storing-state-changes">The Art Of Compromise: CQRS, But Storing State Changes</h2>
<p>SHRINE 1.23 was a skunk-works experiment to show the researchers progress updates as queries moved through the network. We replaced the long, slow, layered web API calls with message-oriented middleware queues to support asynchronous reporting and gain reliability. Queries and results gained more observable events. That fidelity interacted badly with the low quality timestamps; we needed even more cyclomatic complexity to recreate the state.</p>
<p>&quot;Complexity is your Enemy&quot; - Lee Haoyi . We needed some way to limit the complexity of the logic . SHRINE had compute power and IO bandwidth to spare. (The most significant bottleneck in SHRINE - by two orders-of-magnitude or more - is in the patient data source. We could never change that.) The events in SHRINE carry small changes to small pieces of state of progress through the network for a result. The distributed parts of the system that were emitting the events have valid - but possibly outdated - versions of the state. We could take advantage of that.</p>
<p>I took some inspiration from CouchDB/DynamoDB. For SHRINE 2.0 I decided to store state in CQRS style instead of storing simple events. I changed the message meanings from &quot;events&quot; to &quot;proposed state updates&quot; . If the previous state has not changed then SHRINE can safely apply the update. If SHRINE discovers the previous state had changed then some business logic kicks in to decide what to do with the update. For example if a successful result arrives in conflict with a failed result then SHRINE's logic chooses to take with the successful result (as a state after the failed result). Because each state is recorded the states can be replayed. The desired state transitions impose a best order without depending on the unreliable timestamps.</p>
<p>Storing state structures like this is a recommended practice for CouchDB/DynamoDB systems. ... That's not what we used.</p>
<h2 id="more-art-more-compromise-cqrs---but-storing-state---in-a-relational-database">More Art, More Compromise: CQRS - but Storing State - in a Relational Database</h2>
<p><em><a href="https://archive.org/details/stnmnst/JPEG/stnmnst0016.jpg">Famous Blue Muppet does his best to stop you reading more.</a></em></p>
<p>Really - if you can just use CouchDB, or DynamoDB, or something that fits your problem better than late-1980s relational database tables then stop reading, build your system, and go live a happier life. I recommended we store SHRINE's common currency data structures in DynamoDB or CouchDB, with a thin facade to just expose the calls SHRINE needed from either tool. My boss pointed out that our operations team had no experience with either system and were busy with higher priority projects. We needed to store everything in the relational database SHRINE already used.</p>
<p>Later Simon Chang - an amazing operations engineer - and I demonstrated SHRINE 2.0 running with AWS DynamoDB in a 24-hour hack-a-thon in 2019. We got it working in about 4 hours, built a demo with repeated 60-hospital simulated surge tests, had a good night's rest, then put together the presentation in the morning. It worked really well. (... until we burned through the DynamoDB free tier transaction allowance, half-way through showing it to the boss' boss after the party.)</p>
<h2 id="youre-still-reading">You're Still Reading?</h2>
<p><em><a href="https://archive.org/details/stnmnst/JPEG/stnmnst0025.jpg">Famous Blue Muppet pleads with you to read no further.</a></em></p>
<p>Let me see if I can talk you out of the mistake you are about to make by showing some of the code I wrote to get this working in SHRINE. (I guess it wasn't that bad, but we own some complex code when we could have just downloaded a library.)</p>
<p>SHRINE already used Circe to convert its common currency case classes into JSON to transmit in messages and http bodies. SHRINE already supported three brands of database via Slick; we use Slick to save us writing every bit of database code three times. I designed a standard table - and a standard case class trait - to support storing Circe-serialized case classes - using as few database-specific features as possible.</p>
<p>The case classes - at their simplest - look like this:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">case</span> <span class="token keyword">class</span> Researcher<span class="token punctuation">(</span>
                 id<span class="token operator">:</span>ResearcherId <span class="token operator">=</span> ResearcherId<span class="token punctuation">.</span>create<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                 versionInfo<span class="token operator">:</span> VersionInfo <span class="token operator">=</span> VersionInfo<span class="token punctuation">.</span>create<span class="token punctuation">,</span>
                 userName<span class="token operator">:</span>UserName<span class="token punctuation">,</span>
                 userDomainName<span class="token operator">:</span>UserDomainName<span class="token punctuation">,</span>
                 nodeId<span class="token operator">:</span>NodeId
                <span class="token punctuation">)</span> <span class="token keyword">extends</span> Versioned<span class="token punctuation">[</span>ResearcherId<span class="token punctuation">]</span> <span class="token punctuation">{</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">}</span></code></pre>
<p>The itemVersion member in VersionInfo provides an order of states observed in SHRINE's modified CQRS system. (The protocolVersion field supports backwards-compatibility and the other fields are invaluable for debugging.)</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">case</span> <span class="token keyword">class</span> VersionInfo<span class="token punctuation">(</span>
                    protocolVersion<span class="token operator">:</span>ProtocolVersion<span class="token punctuation">,</span>
                    shrineVersion<span class="token operator">:</span>ShrineVersion<span class="token punctuation">,</span>
                    itemVersion<span class="token operator">:</span>ItemVersion<span class="token punctuation">,</span>
                    createDate<span class="token operator">:</span>DateStamp<span class="token punctuation">,</span>
                    changeDate<span class="token operator">:</span>DateStamp<span class="token punctuation">,</span>
            <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">}</span></code></pre>
<p>ItemVersion is just an Int value class:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">class</span> ItemVersion<span class="token punctuation">(</span><span class="token keyword">val</span> underlying<span class="token operator">:</span><span class="token builtin">Int</span><span class="token punctuation">)</span> <span class="token keyword">extends</span> <span class="token builtin">AnyVal</span> <span class="token keyword">with</span> ValueClass<span class="token punctuation">[</span><span class="token builtin">Int</span><span class="token punctuation">]</span></code></pre>
<p>If everything is working smoothly then the itemVersion should increment by one for each recorded change in state for a case class with a given id. SHRINE will insert a new row in a table in the database each time it observes a new state. When SHRINE needs to provide a most-up-to-date view of state it will select the row with the right ID and maxiumun itemVersion, then reconstitute the case class from that row's JSON .</p>
<pre class="language-scala"><code class="language-scala">  <span class="token keyword">def</span> selectResearcherByIdIO<span class="token punctuation">(</span>researcherId<span class="token operator">:</span> ResearcherId<span class="token punctuation">)</span><span class="token operator">:</span> IO<span class="token punctuation">[</span>Option<span class="token punctuation">[</span>Researcher<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token comment">//Select the row with the maximum itemVersion for the id</span>
    runIO<span class="token punctuation">(</span>Researchers<span class="token punctuation">.</span>allRows<span class="token punctuation">.</span>filter<span class="token punctuation">(</span>_<span class="token punctuation">.</span>id <span class="token operator">==</span><span class="token operator">=</span> researcherId<span class="token punctuation">)</span><span class="token punctuation">.</span>sortBy<span class="token punctuation">(</span>_<span class="token punctuation">.</span>itemVersion<span class="token punctuation">.</span>desc<span class="token punctuation">)</span><span class="token punctuation">.</span>take<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span>result<span class="token punctuation">.</span>headOption<span class="token punctuation">)</span><span class="token punctuation">.</span>
      map<span class="token punctuation">(</span> _<span class="token punctuation">.</span>map<span class="token punctuation">(</span>_<span class="token punctuation">.</span>toResearcher<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//convert the JSON to a Researcher</span>
  <span class="token punctuation">}</span></code></pre>
<p>Before SHRINE inserts the new row it checks that there's no row for that id with the itemVersion. If that's true then it inserts the new row:</p>
<pre class="language-scala"><code class="language-scala">      tableCompanion<span class="token punctuation">.</span>allRows<span class="token punctuation">.</span>filter<span class="token punctuation">(</span>r <span class="token keyword">=></span> r<span class="token punctuation">.</span>id <span class="token operator">==</span><span class="token operator">=</span> row<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span>filter<span class="token punctuation">(</span>r <span class="token keyword">=></span> r<span class="token punctuation">.</span>itemVersion <span class="token operator">==</span><span class="token operator">=</span> row<span class="token punctuation">.</span>itemVersion<span class="token punctuation">)</span><span class="token punctuation">.</span>result<span class="token punctuation">.</span>flatMap <span class="token punctuation">{</span>
        <span class="token keyword">case</span> Seq<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">=></span> <span class="token punctuation">{</span> <span class="token comment">// a row with this id and version does not exist yet</span>
          <span class="token comment">//insert the row only if it is the only row with this id and version</span>
          tableCompanion<span class="token punctuation">.</span>allRows <span class="token operator">+=</span> row
        <span class="token punctuation">}</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span>
          <span class="token comment">//expect insertCount to be 1</span></code></pre>
<p>When SHRINE receives data out-of-order, but with the correct itemVersions then SHRINE simply inserts the late data's JSON in the table. The rest of the system can flow without worrying about things written out-of-order in the database.</p>
<p>When SHRINE detects a row with the same id and itemVersion then SHRINE does a simple check to see if the states match. If an identical state is already in the table then it's not a problem; something else wrote the data earlier - which can certainly happen with message-oriented middleware retries. If there's a difference in the JSON then this particular write lost a race. SHRINE's database code fails with an exception so that code with a broader context can decide what to do.</p>
<pre class="language-scala"><code class="language-scala">        <span class="token keyword">case</span> alreadyExists <span class="token keyword">=></span> <span class="token comment">// at least one row with this id and version does exist already</span>
          <span class="token comment">// don't insert the row</span>
          <span class="token comment">// if the existing rows with this id and version are the same then this isn't a problem</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>alreadyExists<span class="token punctuation">.</span>forall<span class="token punctuation">(</span>_ <span class="token operator">==</span> row<span class="token punctuation">)</span><span class="token punctuation">)</span> DBIO<span class="token punctuation">.</span>successful<span class="token punctuation">(</span>None<span class="token punctuation">)</span>
          <span class="token comment">// However, this is a problem if the new row is different from the others</span>
          <span class="token comment">// Due to the transaction this should only happen if some other row was written outside this method</span>
          <span class="token keyword">else</span> DBIO<span class="token punctuation">.</span>failed<span class="token punctuation">(</span>ItemVersionRaceLostException<span class="token punctuation">[</span>I<span class="token punctuation">,</span> V<span class="token punctuation">,</span> R<span class="token punctuation">]</span><span class="token punctuation">(</span>item<span class="token punctuation">,</span> row<span class="token punctuation">,</span> alreadyExists<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>The whole works starts with a write operation to an auxiliary table that exits solely for locking. This lock prevents multiple inserts from happening concurrently on data in the same table. I could have gotten more throughput with a row-per-ID and corresponding lock. I thought of it late, and SHRINE preformed very well without that optimization.</p>
<pre class="language-scala"><code class="language-scala">    <span class="token comment">//increment the table version and isolate this transaction </span>
    incrementTableVersion<span class="token punctuation">(</span>tableCompanion<span class="token punctuation">.</span>tableName<span class="token punctuation">)</span><span class="token punctuation">.</span>flatMap <span class="token punctuation">{</span> _ <span class="token keyword">=></span></code></pre>
<p>In case you're not convinced to just use CouchDB or the like - here's the full, unedited method, with four generics to fill in. It's not the worst code, but requires a lot of supporting bits to make work. Converting Slick's DBIOs to cats effects IOs wraps around this call. Additional code in the IO layer adds business logic to decide how to resolve conflicts shown by ItemVersionRaceLostExceptions.</p>
<pre class="language-scala"><code class="language-scala">  <span class="token keyword">private</span> <span class="token keyword">def</span> upsertItem<span class="token punctuation">[</span>
    I <span class="token operator">&lt;</span><span class="token operator">:</span> Id<span class="token operator">:</span> ClassTag<span class="token punctuation">,</span> <span class="token comment">//Needs the ClassTag to let I survive erasure</span>
    R <span class="token operator">&lt;</span><span class="token operator">:</span> Row<span class="token punctuation">[</span>I<span class="token punctuation">]</span><span class="token punctuation">,</span>
    V <span class="token operator">&lt;</span><span class="token operator">:</span> Versioned<span class="token punctuation">[</span>I<span class="token punctuation">]</span><span class="token punctuation">,</span>
    Items <span class="token operator">&lt;</span><span class="token operator">:</span> ItemTable<span class="token punctuation">[</span>I<span class="token punctuation">,</span>R<span class="token punctuation">]</span>
  <span class="token punctuation">]</span><span class="token punctuation">(</span>
     item<span class="token operator">:</span> V<span class="token punctuation">,</span>
     tableCompanion<span class="token operator">:</span> ItemTableCompanion<span class="token punctuation">[</span>I<span class="token punctuation">,</span>R<span class="token punctuation">,</span>V<span class="token punctuation">,</span>Items<span class="token punctuation">]</span>
   <span class="token punctuation">)</span><span class="token operator">:</span> UpsertItemType<span class="token punctuation">[</span>V<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>

    <span class="token keyword">val</span> row <span class="token operator">=</span> tableCompanion<span class="token punctuation">.</span>itemToRow<span class="token punctuation">(</span>item<span class="token punctuation">)</span>
    <span class="token keyword">implicit</span> <span class="token keyword">val</span> IdColumnType<span class="token operator">:</span> JdbcType<span class="token punctuation">[</span>I<span class="token punctuation">]</span> <span class="token keyword">with</span> BaseTypedType<span class="token punctuation">[</span>I<span class="token punctuation">]</span> <span class="token operator">=</span> MappedColumnType<span class="token punctuation">.</span>base<span class="token punctuation">[</span>I<span class="token punctuation">,</span> <span class="token builtin">Long</span><span class="token punctuation">]</span><span class="token punctuation">(</span>
      id <span class="token keyword">=></span> id<span class="token punctuation">.</span>underlying<span class="token punctuation">,</span>
      long <span class="token keyword">=></span> tableCompanion<span class="token punctuation">.</span>longToId<span class="token punctuation">(</span>long<span class="token punctuation">)</span>
    <span class="token punctuation">)</span>

    <span class="token comment">//increment the table version and isolate this transaction </span>
    incrementTableVersion<span class="token punctuation">(</span>tableCompanion<span class="token punctuation">.</span>tableName<span class="token punctuation">)</span><span class="token punctuation">.</span>flatMap <span class="token punctuation">{</span> _ <span class="token keyword">=></span>
      <span class="token comment">// Find all the rows with the same id and version number</span>
      tableCompanion<span class="token punctuation">.</span>allRows<span class="token punctuation">.</span>filter<span class="token punctuation">(</span>r <span class="token keyword">=></span> r<span class="token punctuation">.</span>id <span class="token operator">==</span><span class="token operator">=</span> row<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span>filter<span class="token punctuation">(</span>r <span class="token keyword">=></span> r<span class="token punctuation">.</span>itemVersion <span class="token operator">==</span><span class="token operator">=</span> row<span class="token punctuation">.</span>itemVersion<span class="token punctuation">)</span><span class="token punctuation">.</span>result<span class="token punctuation">.</span>flatMap <span class="token punctuation">{</span>
        <span class="token keyword">case</span> Seq<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">=></span> <span class="token punctuation">{</span> <span class="token comment">// a row with this id and version does not exist yet</span>
          <span class="token comment">//insert the row only if it is the only row with this id and version</span>
          tableCompanion<span class="token punctuation">.</span>allRows <span class="token operator">+=</span> row
        <span class="token punctuation">}</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span>
          <span class="token comment">//expect insertCount to be 1</span>
          <span class="token keyword">case</span> ic <span class="token keyword">if</span> ic <span class="token operator">==</span> <span class="token number">1</span> <span class="token keyword">=></span> Some<span class="token punctuation">(</span>item<span class="token punctuation">)</span>
          <span class="token keyword">case</span> insertCount<span class="token operator">:</span> <span class="token builtin">Int</span> <span class="token keyword">=></span> <span class="token keyword">throw</span> HubDatabaseAssertException<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token id function">s</span><span class="token string">"""insert into </span><span class="token interpolation"><span class="token punctuation">${</span><span class="token expression">tableCompanion<span class="token punctuation">.</span>tableName</span><span class="token punctuation">}</span></span><span class="token string"> returned </span><span class="token interpolation"><span class="token punctuation">$</span><span class="token expression">insertCount</span></span><span class="token string">, not 1 as expected"""</span></span><span class="token punctuation">)</span> <span class="token comment">// ic == 0 would mean nothing was inserted. I don't think ic > 1  can happen</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">case</span> alreadyExists <span class="token keyword">=></span> <span class="token comment">// at least one row with this id and version does exist already</span>
          <span class="token comment">// don't insert the row</span>
          <span class="token comment">// if all the existing rows with this id and version are the same then this isn't a problem</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>alreadyExists<span class="token punctuation">.</span>forall<span class="token punctuation">(</span>_ <span class="token operator">==</span> row<span class="token punctuation">)</span><span class="token punctuation">)</span> DBIO<span class="token punctuation">.</span>successful<span class="token punctuation">(</span>None<span class="token punctuation">)</span>
          <span class="token comment">// However, this is a problem if the new row is different from the others</span>
          <span class="token comment">// Due to the transaction this should only happen if some other row was written outside this method</span>
          <span class="token keyword">else</span> DBIO<span class="token punctuation">.</span>failed<span class="token punctuation">(</span>ItemVersionRaceLostException<span class="token punctuation">[</span>I<span class="token punctuation">,</span> V<span class="token punctuation">,</span> R<span class="token punctuation">]</span><span class="token punctuation">(</span>item<span class="token punctuation">,</span> row<span class="token punctuation">,</span> alreadyExists<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<p>Examining the generated SQL showed that almost everything in this method happened within one prepared statement in the database. Most of the time to make the call is connection and transmit overhead to get out of the JVM and into the database's process. It's pretty efficient.</p>
<p>All-in-all this worked very well for SHRINE 2.0 to SHRINE 4.3 - about five years of production use. That upsert() is probably the most involved method I wrote and didn't delete in SHRINE's codebase. It has the feel of a senior class project to teach us how something complex works. I'm happy it works well, but there are easier off-the-shelf tools to get CQRS working. It's something other people could use but probably shouldn't.</p>
<p><em><a href="https://archive.org/details/stnmnst/JPEG/stnmnst0028.jpg">Famous Blue Muppet, relieved, is so embarrassed.</a></em></p>
<hr>
<h2 id="a-note-on-famous-blue-muppet">A Note on &quot;Famous Blue Muppet&quot;</h2>
<p><strong>1.</strong> The interruptions above are Grover's, from Jon Stone's <em>The Monster at the
End of This Book</em>, illustrated by Michael Smollin. Each one links to a page of
the <a href="https://archive.org/details/stnmnst">Internet Archive's scan</a>. I swapped the images out for links when I restarted this blog in mid-2026. Recent advances in AI have made me very sensitive to copyright.</p>
<p>Jon Stone wrote this amazing book about dread, anticipation, and the gap between the two. It makes a great introduction to a discussion of The Sunk Cost Fallacy. It is essential reading alongside critiques of software development lifecycle trends.</p>
<p>You should own a physical copy. The book can express your concerns very quickly, but it does not work on a screen. You don't want some Famous Blue Muppet sabotaging your trackpad.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The New Hire Plan</title>
      <link>https://blog.walend.net/2024/03/the-new-hire-plan/</link>
      <guid isPermaLink="true">https://blog.walend.net/2024/03/the-new-hire-plan/</guid>
      <pubDate>Thu, 28 Mar 2024 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <description>In the first two days of a new job I get the code building and one small change checked in. When I lead, I plan the first weeks and months the same way.</description>
      <content:encoded><![CDATA[<p>In the first two days of a new job I like to get the code checked out, building in my environment, then get some small change tested, and checked in where others can see it. Exercising that simple development loop sets the tone for the first weeks, and reassures everyone that I'll be able to contribute. When I am in a lead position - bringing new interns or employees on projects I run - I take things a step further. Beyond that first code change I find small projects that show important concepts for the first weeks, and a larger project with significant impact for the first few months. I often have that first project in mind while I am interviewing.</p>
<p>My boss' direction for our first intern at HMS was, &quot;Just drop him into the project and treat him like any other software engineer on the team.&quot; We hadn't had any developers join the team since I had been hired two years prior, so I took it as a license to pull from my experience, especially as tech lead for a growing team at BAE. I came up with some steps that matched what I would want for myself, and steps that I thought would get that engineer up to speed quickly. We used the process successfully with four interns and one new employee at HMS Catalyst.</p>
<p>I had led something similar for a dozen new hires at BAE. There we had the new hires give a presentation to the whole team in the first few weeks to introduce themselves and show how their experience would help us. We had an ulterior motive; we were doing defense research and could never predict who might be read into which compartment and suddenly be called on to present to a customer. (Misadventures followed, but it all worked out.) At HMS the interns gave a presentation on what they had done at the end of their term.</p>
<p>MathWorks had a very well-thought-out monthly orientation class for all new employees about how the company worked. (MathWorks put thought into everything.) It was really good, but at a more grand scale than I would expect anywhere else ... ever. When I listed what I wanted to do in my first few days at MathWorks my boss there replied with something like, &quot;Yes, that's what we want you to do. Sign up for the orientation class.&quot; MathWorks was already doing what I thought was a good idea.</p>
<p>I think these steps would work well anywhere, when combined with the 20-minute rule (... a future blog entry):</p>
<p>Day 1 - Get a computer working with internal systems, check out the code, get it to build, start on an easy ticket.</p>
<p>Day 2 - Finish the fix for that easy ticket, check it in, ask for a review.</p>
<p>Day 3 - Merge that change into a git branch headed for a release.</p>
<p>Weeks 1 &amp; 2 - Get a grand tour of key libraries and concepts central to our product by fixing more interesting tickets.</p>
<p>Week 3 and onward - Take on some major, unifying project that works across teams and has a deep impact to learn to work &quot;like any other software engineer on the team.&quot;</p>
<p>Some time in the first four months - Present something relevant to the team.</p>
<p>To follow that plan I had to set the stage for the new hires before they started. I was able to delegate getting set up as a Harvard employee and getting a laptop going; I'm grateful others could help navigate the bureaucracy. The software tasks were easy to find. I had inherited a Jira system with hundreds of open tickets to sieve. We were moving SHRINE through a major architectural transformation from a promising prototype to a resilient system. I had to balance difficulty of a change, value of that change, and the risk that a new hire would get lost and need more help than the team could provide. The interns needed good stories to tell for job interviews, which eliminated some of the more arduous SHRINE-specific tasks and wholesale deleting of dead code. The limit came from abundance of work and my own limited time to coach.</p>
<p>Unit tests and cosmetic changes provided early, easy tickets. This also made completing these &quot;fold the laundry&quot; sorts of tasks more valuable than using them as fill at the end of sprints.</p>
<p>The Jira backlog provided tasks for the tour of key libraries and concepts. SHRINE uses http4s for its web API, cats effects for concurrency, CQRS via slick for database work (Our first intern could not contain his delight about writing monadic database code on day three.), AWS SQS for messaging, circe for json, i2b2 as a source of patient data, and Scala's xml library to read and write i2b2's xml. I found a ticket in each of these categories to fix some minor bug or make some minor improvement. I could usually line the tasks up in an order that built one skill on another.</p>
<p>New features provided that important project. I gave interns major responsibility; that freed me to lead the project, manage day-to-day tasks, and deal with the crisis of the moment. The projects included things like &quot;simplify the query sign/verify code&quot; and &quot;create and fill in the API we will use for message-oriented middleware.&quot; The one employee who started under my watch had more than a decade of experience at HMS Catalyst, so I asked her to &quot;pick a web API library to replace Jakarta and Spray, then rework the web API endpoints to use that library,&quot; a very broad project. She was a bit taken aback by that, but she gained expertise, then shared it. It couldn't have worked better.</p>
<p>Some parts of our work were simply not good tasks for new hires. Some of the vital parts of SHRINE - especially communicating with i2b2 - required years to accumulate all the unstated caveats. Refactoring tangled code or deleting obsolete subsystems would just frustrate a new developer without helping them learn the system. It's more efficient to have an old hand (me) clean up the mess and refactor it to something easier to understand. The new hires can help review the change to get that understanding of the improved code.</p>
<p>Overall this new hire process worked so well I decided to use it as my first blog entry for the 2024 blogging restart. Next time I start a new job or hire someone new I hope to follow it and learn a little more about how to start a job right.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Implicit Pimp Suspicion</title>
      <link>https://blog.walend.net/2016/06/Pimping-Config/</link>
      <guid isPermaLink="true">https://blog.walend.net/2016/06/Pimping-Config/</guid>
      <pubDate>Mon, 13 Jun 2016 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <description>I&#39;m very suspicious of Scala&#39;s implicits and the pimp pattern. I pimped Typesafe Config&#39;s Config class to handle case class apply() constructors and Options.</description>
      <content:encoded><![CDATA[<p>TL/DR - I'm very suspicious of Scala's implicits and the pimp pattern. I pimped Typesafe Config's Config class to handle case class apply() constructors and Options. I pimped my undirected graph class to correct results for Brandes' algorithm. Maybe I'm getting over it.</p>
<h1 id="explicit-implicit">Explicit Implicit</h1>
<p>Before I read Pragmatic Programmer I knew I wanted to make my programs transparent and easy to understand. Thomas and Hunt have a section devoted to <a href="https://pragprog.com/the-pragmatic-programmer/extracts/coincidence">&quot;Explicit Programming,&quot;</a> the idea of making a piece of code as clear and non-magical possible. Scala's implicits seem like an anathema of that goal. I've mostly avoided implicits, and mostly regretted it when I haven't.</p>
<h1 id="i-wish-typesafe-config-knew-about-scala">I Wish Typesafe Config Knew About Scala</h1>
<p>I like Typesafe Config. However, it's in Java so the API is awkwardly broad. Config was pulled out of Akka; it shouldn't seem so alien. To support primitives the Config object has a herd of narrowly-typed get*() methods. To use Config I'm expected to pull out ints and booleans and Strings, and, piece-by-piece, collect little parts. I wish it had more of a Scala-style API, something that would let me hand in a higher order function and give me back a finished whole instance of things I do care about.</p>
<p>I could use the pimp pattern to get what I want.</p>
<h1 id="pimp-pattern">Pimp Pattern</h1>
<p>Scala offers the <a href="https://coderwall.com/p/k_1jzw/scala-s-pimp-my-library-pattern-example">Pimp Pattern</a> to add API to classes we don't control. I was suspicious. One thing I like in Scala is that I don't need the <a href="http://alvinalexander.com/scala/how-scala-killed-oop-strategy-design-pattern#What_about_those_other_OOP_design_patterns">Gang-of-Four Pattern Book</a>; after 20 years of Java I've had enough patterns. <a href="https://en.wikipedia.org/wiki/Doctor_Detroit">Pimps are comic bad guys in B movies</a>. The Pimp Pattern relies on [implicits](http://twitter.github.io/effectivescala/#Types and Generics-Implicits), which seem like a good way to make spaghetti code, far from my explicit ideals. That's three bad smells before I've even started.</p>
<p>I tried it despite my misgivings. I pimped Config. I added higher order functions to make getters to give me the actual parts I care about instead of just primitives. To use it I still explicitly import the parts. The rest just works:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">import</span> <span class="token namespace">net<span class="token punctuation">.</span>shrine<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span>ConfigExtensions
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">val</span> config<span class="token operator">:</span> Config <span class="token operator">=</span> ConfigFactory<span class="token punctuation">.</span>load<span class="token punctuation">(</span><span class="token string">"shrine"</span><span class="token punctuation">)</span>
<span class="token keyword">val</span> keyStoreDescriptor <span class="token operator">=</span> config<span class="token punctuation">.</span>getConfigured<span class="token punctuation">(</span><span class="token string">"shrine.keystore"</span><span class="token punctuation">,</span>KeyStoreDescriptor<span class="token punctuation">(</span>_<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>KeyStoreDescriptor's companion object has an <a href="https://blog.walend.net/2016/05/Applying-Typesafe-Config/">apply(Config)</a> method that makes a KeyStoreDescriptor. I ask Config for what I want through very clean, very intuitive code.</p>
<p>Here's the code for ConfigExtensions:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">package</span> <span class="token namespace">net<span class="token punctuation">.</span>shrine</span>

<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>typesafe<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span>Config

<span class="token keyword">package</span> <span class="token namespace">object</span> config <span class="token punctuation">{</span>

  <span class="token keyword">implicit</span> <span class="token keyword">class</span> ConfigExtensions<span class="token punctuation">(</span><span class="token keyword">self</span><span class="token operator">:</span> Config<span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token keyword">def</span> get<span class="token punctuation">[</span>T<span class="token punctuation">]</span><span class="token punctuation">(</span>key<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>construct<span class="token operator">:</span><span class="token builtin">String</span> <span class="token keyword">=></span> T<span class="token punctuation">)</span><span class="token operator">:</span>T <span class="token operator">=</span> construct<span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>getString<span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> getConfigured<span class="token punctuation">[</span>T<span class="token punctuation">]</span><span class="token punctuation">(</span>key<span class="token operator">:</span> <span class="token builtin">String</span><span class="token punctuation">,</span> constructor<span class="token operator">:</span> Config <span class="token keyword">=></span> T<span class="token punctuation">)</span><span class="token operator">:</span> T <span class="token operator">=</span> constructor<span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>getConfig<span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
  <span class="token punctuation">}</span></code></pre>
<p>The implicit class has to exist inside another class or object definition or else the compiler growls about an `implicit' modifier cannot be used for top-level objects'. However, the package object works fine and gets the class into a natural namespace, only one step from explicitly having ConfigExtensions in its own file. (Other people seem to use a class or a trait as a namespace to hold the implicit class. The class approach tempts coders into using a wildcard import, hiding the magical pimp behind more smoke and another mirror. Extending the trait to get access to methods in a class' context seems to make the class claim to essentially be something it isn't, inviting an OO tangle.)</p>
<p>I'm half-tempted to suggest a Scala language fix to let the implicit class just be part of a package instead of junking up my package object. I want a better understanding of why things are done this way first.</p>
<h1 id="code-caught-between">Code Caught Between</h1>
<p>For a directed graph <a href="http://dwalend.github.io/Disentangle/v0.2.1/#net.walend.disentangle.graph.semiring.Brandes$">Brandes' Algorithm</a> counts how many times a node appears in the shortest path from one node to another. To run Brande's Algorithm on an undirected graph, convert each undirected edge into two directed edges (one each way), run the calculation, then divide the counts by two - because the algorithm finds two paths in the directed graph for every path that exists in the undirected graph.</p>
<p>In <a href="https://github.com/dwalend/Disentangle">Disentangle</a> the <a href="http://dwalend.github.io/Disentangle/v0.2.1/#net.walend.disentangle.graph.semiring.package">algorithm code</a> is decoupled from the <a href="http://dwalend.github.io/Disentangle/v0.2.1/#net.walend.disentangle.graph.package">graph structures</a>. The parameters for algorithms are collections of edges and nodes, not graphs. Up until Brandes' algorithm on undirected graphs I was comfortable writing explicit, simple glue code to access lists of edges to feed the algorithms. I didn't want to force my users to convert to Disentangle's graph structures in order to access the algorithms, and didn't want parts of my algorithms escaping into the graph code.</p>
<p>I trust people to convert from undirected to directed graphs; mistakes will give spectacular wrong answers. However, Brandes' &quot;finally divide the results by two&quot; would be easy to leave out; betweenness would still just be a big Map from nodes to unintuitive numbers. I had no good place to hang the divide-by-two correction.</p>
<h1 id="return-of-the-pimp">Return of the Pimp</h1>
<p>That pimp pattern let me inject a new method on the undirected graph trait; using Brandes' algorithm looks like just another method call:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">package</span> <span class="token namespace">net<span class="token punctuation">.</span>walend<span class="token punctuation">.</span>disentangle<span class="token punctuation">.</span>examples</span>

<span class="token keyword">import</span> <span class="token namespace">net<span class="token punctuation">.</span>walend<span class="token punctuation">.</span>disentangle<span class="token punctuation">.</span>graph<span class="token punctuation">.</span>semiring<span class="token punctuation">.</span></span>Brandes<span class="token punctuation">.</span>BrandesSteps
<span class="token keyword">import</span> <span class="token namespace">net<span class="token punctuation">.</span>walend<span class="token punctuation">.</span>disentangle<span class="token punctuation">.</span>graph<span class="token punctuation">.</span>semiring<span class="token punctuation">.</span></span>LabelUndigraphSemiringAlgorithms
<span class="token keyword">import</span> <span class="token namespace">net<span class="token punctuation">.</span>walend<span class="token punctuation">.</span>disentangle<span class="token punctuation">.</span>graph<span class="token punctuation">.</span></span><span class="token punctuation">{</span>AdjacencyLabelUndigraph<span class="token punctuation">,</span> NodePair<span class="token punctuation">}</span>

<span class="token keyword">object</span> BrandesImplicitsExample <span class="token punctuation">{</span>
  <span class="token keyword">val</span> edges<span class="token operator">:</span> Seq<span class="token punctuation">[</span><span class="token punctuation">(</span>NodePair<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> Seq<span class="token punctuation">(</span>
    <span class="token punctuation">(</span>NodePair<span class="token punctuation">(</span><span class="token string">"A"</span><span class="token punctuation">,</span><span class="token string">"B"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token string">"ab"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">)</span>

  <span class="token keyword">val</span> nodeOrder <span class="token operator">=</span> Array<span class="token punctuation">(</span><span class="token string">"A"</span><span class="token punctuation">,</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"D"</span><span class="token punctuation">,</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"F"</span><span class="token punctuation">,</span><span class="token string">"H"</span><span class="token punctuation">)</span>

  <span class="token keyword">val</span> graph <span class="token operator">=</span> AdjacencyLabelUndigraph<span class="token punctuation">(</span>edges<span class="token punctuation">,</span>nodeOrder<span class="token punctuation">)</span>

  <span class="token keyword">val</span> brandesResults <span class="token operator">=</span> graph<span class="token punctuation">.</span>allLeastPathsAndBetweenness<span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
  <span class="token keyword">val</span> betweennessValues<span class="token operator">:</span> Map<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">Double</span><span class="token punctuation">]</span> <span class="token operator">=</span> brandesResults<span class="token punctuation">.</span>_2
<span class="token punctuation">}</span></code></pre>
<p>The <a href="https://github.com/dwalend/Disentangle/blob/master/graph/src/main/scala/net/walend/disentangle/graph/semiring/package.scala">code</a> looks like this:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">package</span> <span class="token namespace">object</span> semiring <span class="token punctuation">{</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

  <span class="token keyword">implicit</span> <span class="token keyword">class</span> LabelUndigraphSemiringAlgorithms<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>Label<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token operator">:</span> LabelUndigraph<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>Label<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">def</span> allLeastPathsAndBetweenness<span class="token punctuation">[</span>CoreLabel<span class="token punctuation">,</span> Key<span class="token punctuation">]</span><span class="token punctuation">(</span> coreSupport<span class="token operator">:</span> SemiringSupport<span class="token punctuation">[</span>CoreLabel<span class="token punctuation">,</span> Key<span class="token punctuation">]</span> <span class="token operator">=</span> FewestNodes<span class="token punctuation">,</span>
                                                     labelForEdge<span class="token operator">:</span> <span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> Label<span class="token punctuation">)</span> <span class="token keyword">=></span> CoreLabel <span class="token operator">=</span> FewestNodes<span class="token punctuation">.</span>edgeToLabelConverter<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token punctuation">(</span>IndexedSeq<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> Option<span class="token punctuation">[</span>BrandesSteps<span class="token punctuation">[</span>Node<span class="token punctuation">,</span> CoreLabel<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> Map<span class="token punctuation">[</span>Node<span class="token punctuation">,</span> <span class="token builtin">Double</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
      <span class="token keyword">val</span> digraphResult <span class="token operator">=</span> <span class="token keyword">self</span> <span class="token keyword">match</span> <span class="token punctuation">{</span>
        <span class="token keyword">case</span> indexed<span class="token operator">:</span>IndexedLabelDigraph<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>Label<span class="token punctuation">]</span> <span class="token keyword">=></span> Brandes<span class="token punctuation">.</span>allLeastPathsAndBetweenness<span class="token punctuation">(</span>indexed<span class="token punctuation">.</span>edges<span class="token punctuation">,</span>indexed<span class="token punctuation">.</span>nodes<span class="token punctuation">.</span>asSeq<span class="token punctuation">,</span>coreSupport<span class="token punctuation">,</span>labelForEdge<span class="token punctuation">)</span>
        <span class="token keyword">case</span> _ <span class="token keyword">=></span> Brandes<span class="token punctuation">.</span>allLeastPathsAndBetweenness<span class="token punctuation">(</span>diEdges<span class="token punctuation">,</span>coreSupport <span class="token operator">=</span> coreSupport<span class="token punctuation">,</span>labelForEdge <span class="token operator">=</span> labelForEdge<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      correctForUndigraph<span class="token punctuation">(</span>digraphResult<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">def</span> diEdges<span class="token operator">:</span> GenTraversable<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> Label<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
      <span class="token keyword">self</span><span class="token punctuation">.</span>edges<span class="token punctuation">.</span>map<span class="token punctuation">(</span>e <span class="token keyword">=></span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>_1<span class="token punctuation">.</span>_1<span class="token punctuation">,</span>e<span class="token punctuation">.</span>_1<span class="token punctuation">.</span>_2<span class="token punctuation">,</span>e<span class="token punctuation">.</span>_2<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token keyword">self</span><span class="token punctuation">.</span>edges<span class="token punctuation">.</span>map<span class="token punctuation">(</span>e <span class="token keyword">=></span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>_1<span class="token punctuation">.</span>_2<span class="token punctuation">,</span>e<span class="token punctuation">.</span>_1<span class="token punctuation">.</span>_1<span class="token punctuation">,</span>e<span class="token punctuation">.</span>_2<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">def</span> correctForUndigraph<span class="token punctuation">[</span>CoreLabel<span class="token punctuation">]</span><span class="token punctuation">(</span>digraphResult<span class="token operator">:</span> <span class="token punctuation">(</span>IndexedSeq<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> Option<span class="token punctuation">[</span>BrandesSteps<span class="token punctuation">[</span>Node<span class="token punctuation">,</span> CoreLabel<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> Map<span class="token punctuation">[</span>Node<span class="token punctuation">,</span> <span class="token builtin">Double</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
      <span class="token keyword">val</span> halfMap <span class="token operator">=</span> digraphResult<span class="token punctuation">.</span>_2<span class="token punctuation">.</span>map<span class="token punctuation">(</span>x <span class="token keyword">=></span> <span class="token punctuation">(</span>x<span class="token punctuation">.</span>_1<span class="token punctuation">,</span>x<span class="token punctuation">.</span>_2<span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span>digraphResult<span class="token punctuation">.</span>_1<span class="token punctuation">,</span>halfMap<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>     
<span class="token punctuation">}</span></code></pre>
<p>Again I put the implicit class in the package object to keep it in what feels like the right namespace. That code seems OK, so I added methods for other algorithms, did the same for directed graphs, and released it as <a href="https://github.com/dwalend/Disentangle#changes-in-021-the-fifth-release">Disentangle 0.2.1</a>.</p>
<p>I'm still openly suspicious of implicits. I wouldn't want to work with a whole library magically tacked together this way. However, using the pimp pattern to contain methods that would otherwise be drifting around in unrelated, undiscoverable code seems OK so far.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Just apply(Config)</title>
      <link>https://blog.walend.net/2016/05/Applying-Typesafe-Config/</link>
      <guid isPermaLink="true">https://blog.walend.net/2016/05/Applying-Typesafe-Config/</guid>
      <pubDate>Fri, 20 May 2016 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <description>Try using apply methods in companion objects that take values from a TypeSafe Config instance parameter.</description>
      <content:encoded><![CDATA[<p>TL/DR - I started using apply methods in companion objects that take a TypeSafe Config instance parameter. Now I am much happier.</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">object</span> UsefulConfigurableThing <span class="token punctuation">{</span>
    <span class="token keyword">def</span> apply<span class="token punctuation">(</span>config<span class="token operator">:</span>Config<span class="token punctuation">)</span><span class="token operator">:</span>UsefulConfigurableThing <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>I use this method to make standard parts easy to configure. I let things be even simpler for singletons - a singleton just accesses the Config it needs. The resulting code is clear and very flat. Competing options meant filing my head with a new bag of API names and sometimes a new skill in an uninteresting discipline. This flat approach saves me from depending on a mountain of YANGTNI framework features.</p>
<h1 id="shrines-use-of-typesafe-config">SHRINE's use of TypeSafe Config</h1>
<p>For my day-job I work on work on an open-source bioinformatics project called <a href="https://catalyst.harvard.edu/services/shrine/">SHRINE</a>. I'm (mostly) fortunate to have inherited a project that is a business success built on well-tested code. SHRINE started life as &quot;Scala-as-a-better-Java,&quot; first check-in I can find was in 2008. SHRINE is cradled inside a Tomcat servlet behind Jersey, and needs some weeding. (I'm slowly refactoring it toward less baroque dependencies - a different rant.) It has a lot of config. We fix about a third of SHRINE troubles in the field by tweaking a node's shrine.config file. Our team needs to be able to quickly trace what a configuration value does in the code.</p>
<p>At the bottom of the stack is TypeSafe Config, which is really quite good. However, the optional config of optional parts with optional parts that a eight-year-old project develops leave their scars, and SHRINE's config is warty. One of the background whispers in the code is a fear of breaking things that work. I spotted four themes written in the code: &quot;ManuallyWiredShrineJaxrsResources,&quot; plus two layers of empty case classes (and tests) as middle stages between Typesafe Config and the actual places that use the configured values hint that at least one of my predecessors really missed having Spring handle his configuration. He expected to use those extra layers for validation, but never did. At least one of other predecessor really didn't understand that this earlier predecessor had built mini-Spring. A third predecessor added a layer of higher-order functions for a different sort of <a href="http://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html#dependency-injection">dependency injection</a>, but had stopped before using those functions more than once. I'm the first developer to use Config's reference.conf files. I might be the first to use a deep embrace of TypeSafe Config.</p>
<p>When our team tries to gain some quick understanding to help system admins in the field we flounder around tracing variables to configured values. We struggle to provide timely support on the phone or in chat because tracing through the code takes too long. It frustrates us. The whole thing should be simpler. After all, it is just config.</p>
<h1 id="systemgetproperty">System.getProperty()</h1>
<p>In Java we started with java.lang.System.getProperty() back in the Age of Plaid Flannel. System.getProperty() was pretty solid and is still in wide use. Everyone understood that Properties was a HashMap[String,String] just from the API. You could stuff values into it from the command line (provided you didn't have too many characters for DOS). java.lang.System.setProperty() had problems that predicted the general goodness of immutability and were easy to avoid. The main work was figuring out what the property keys were. It was great for just getting a database name, password, and url.</p>
<h1 id="cake-spring-di-and-jndi">Cake, Spring, DI, and JNDI</h1>
<p>Sun created a standard called <a href="http://www.oracle.com/technetwork/java/jndi/">JNDI</a>, declared that we should use it, and used it as underpinning for whole fleet of standards. JNDI had two big problems: First, the API is full of uninspiring boilerplate like InitialContext and catching NamingExceptions. Second, you had to supply something to be the back-end for it - almost always a big framework that you program in an XML schema that will be different from the next big framework's XML schema. <a href="https://projects.spring.io/spring-framework/">Spring</a> made it so that I could get my own Java POJ object out the other end, and made the XML schema a bit better, but I was still programming in XML. The <a href="http://www.cakesolutions.net/teamblogs/2011/12/19/cake-pattern-in-depth">Cake Pattern</a> finally let me program in something not XML, in exchange for lots of traits. Someone finally <a href="http://www.cakesolutions.net/teamblogs/2011/12/15/dependency-injection-vs-cake-pattern">formalized what they meant by dependency injection</a> while declaring its alternatives &quot;dinosaurs.&quot; Understanding that helped me conclude that <a href="http://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html#hardcode-it">most of the time I didn't want it in my system</a>.</p>
<p>(Is anyone else bothered that the &quot;DI&quot; in JNDI means something completely different and predates &quot;DI&quot; by five years or more? Maybe Oracle should make it a backronym.)</p>
<h1 id="finally-typesafe-config">Finally TypeSafe Config</h1>
<p>The Akka project spun out <a href="https://github.com/typesafehub/config">TypeSafe Config</a> as a separate project. The gritty details fit on a single, short readme.md page in github, and <a href="https://github.com/typesafehub/config#api-example">the API example fits on a screen</a>. Most of the page is about corner-case features that I don't use frequently. You program TypeSafe Config in a superset of JSON that basically lets you leave out quotes. A Config is a container of key -&gt; object pairs. All of the objects are built from JSON strings. Many of the objects built are Configs. Most of the breadth of the API is about getting the right type into Java.</p>
<h1 id="def-applyconfigconfig-is-enough">def apply(config:Config) is Enough</h1>
<p>I settled on using an apply(Config) method in a case class' companion object as my standard approach.</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">case</span> <span class="token keyword">class</span> StewardQueryAuthorizationService<span class="token punctuation">(</span>qepUserName<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>
                                            qepPassword<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>
                                            stewardBaseUrl<span class="token operator">:</span>URL<span class="token punctuation">,</span>
                                            defaultTimeout<span class="token operator">:</span>FiniteDuration <span class="token operator">=</span> <span class="token number">10</span> seconds<span class="token punctuation">)</span> <span class="token keyword">extends</span> 
             QueryAuthorizationService <span class="token keyword">with</span> 
             Loggable <span class="token keyword">with</span> 
             Json4sSupport <span class="token punctuation">{</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">}</span> 
 
<span class="token keyword">object</span> StewardQueryAuthorizationService <span class="token punctuation">{</span>

  <span class="token keyword">def</span> apply<span class="token punctuation">(</span>config<span class="token operator">:</span>Config<span class="token punctuation">)</span><span class="token operator">:</span>StewardQueryAuthorizationService <span class="token operator">=</span> StewardQueryAuthorizationService <span class="token punctuation">(</span>
    qepUserName <span class="token operator">=</span> config<span class="token punctuation">.</span>getString<span class="token punctuation">(</span><span class="token string">"qepUserName"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    qepPassword <span class="token operator">=</span> config<span class="token punctuation">.</span>getString<span class="token punctuation">(</span><span class="token string">"qepPassword"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    stewardBaseUrl <span class="token operator">=</span> config<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"stewardBaseUrl"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> URL<span class="token punctuation">(</span>_<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p>The apply() method pulls arguments from the Config for the case class' constructor, then calls the case class. JSON to case class. Standard, general tools. No special skills or big patterns to explain. No mystery.</p>
<h1 id="sometimes-applyconfig-is-more-than-enough">Sometimes apply(Config) is More Than Enough</h1>
<p>That technique works great in general, but sometimes there'd only be one instance of the class. A Scala object is a better choice. For that, I apply Li Haoyi's principle of least power. I go one step further than hard-coding, and pull the value out of the Config exactly where I need it.</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">object</span> StewardSchema <span class="token punctuation">{</span>

  <span class="token keyword">val</span> allConfig<span class="token operator">:</span>Config <span class="token operator">=</span> StewardConfigSource<span class="token punctuation">.</span>config
  <span class="token keyword">val</span> config<span class="token operator">:</span>Config <span class="token operator">=</span> allConfig<span class="token punctuation">.</span>getConfig<span class="token punctuation">(</span><span class="token string">"shrine.steward.database"</span><span class="token punctuation">)</span>

  <span class="token keyword">val</span> slickProfileClassName <span class="token operator">=</span> config<span class="token punctuation">.</span>getString<span class="token punctuation">(</span><span class="token string">"slickProfileClassName"</span><span class="token punctuation">)</span>
  <span class="token keyword">val</span> slickProfile<span class="token operator">:</span>JdbcProfile <span class="token operator">=</span> StewardConfigSource<span class="token punctuation">.</span>objectForName<span class="token punctuation">(</span>slickProfileClassName<span class="token punctuation">)</span>

  <span class="token keyword">val</span> schema <span class="token operator">=</span> StewardSchema<span class="token punctuation">(</span>slickProfile<span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p>Did you notice that StewardConfigSource.config? Sometimes I need some control over the configuration for testing. I've already <a href="https://blog.walend.net/2015/06/Test-With-TypeSafeConfig/">blogged about how I inject new config variables for testing</a>. That does put in one extra hop to answer &quot;Where does this Config come from?&quot; However, outside of testing anyone's first guess will be right. I've preserved the most important easy answer for &quot;How do I control this value?&quot;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Parallel Disentangle</title>
      <link>https://blog.walend.net/2015/11/Easy-Parallel/</link>
      <guid isPermaLink="true">https://blog.walend.net/2015/11/Easy-Parallel/</guid>
      <pubDate>Tue, 10 Nov 2015 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <description>I added parallel versions of Dijkstra&#39;s and Brandes&#39; algorithms to Disentangle. Writing the code was easy. Consider using them above about 100 nodes.</description>
      <content:encoded><![CDATA[<script type="text/javascript" src="https://blog.walend.net/disentangleParGraphs/js/d3.v3.js">
</script>
<script type="text/javascript" src="https://blog.walend.net/disentangleParGraphs/js/queue.js">
</script>
<script type="text/javascript" src="https://blog.walend.net/disentangleParGraphs/js/plot.js">
</script>
<style type="text/css">

path {
stroke-width: 2;
fill: none;
}

.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}

.axis text {
font-family: sans-serif;
font-size: 10px;
}
</style>
<p>TL/DR - I added parallel versions of Dijkstra's and Brandes' algorithms to Disentangle. Writing the code was easy. Consider using  parallel versions of these algorithms when you've got more than about 100 nodes in your graph and you have computational power to spare. Call them via</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">val</span> simpleShortPathLabelsFromPar <span class="token operator">=</span> Dijkstra<span class="token punctuation">.</span>parAllPairsShortestPaths<span class="token punctuation">(</span>edges<span class="token punctuation">)</span>

<span class="token keyword">val</span> leastPathLabelsFromPar <span class="token operator">=</span> Dijkstra<span class="token punctuation">.</span>parAllPairsLeastPaths<span class="token punctuation">(</span>edges<span class="token punctuation">,</span>support<span class="token punctuation">,</span>labelForEdge<span class="token punctuation">)</span>

<span class="token keyword">val</span> shortestPathsAndBetweennessFromPar <span class="token operator">=</span> Brandes<span class="token punctuation">.</span>parAllLeastPathsAndBetweenness<span class="token punctuation">(</span>edges<span class="token punctuation">)</span></code></pre>
<p>Pull in the latest snapshot with</p>
<pre class="language-scala"><code class="language-scala">resolvers <span class="token operator">+=</span> <span class="token string">"Sonatype OSS Snapshots"</span> at <span class="token string">"https://oss.sonatype.org/content/repositories/snapshots"</span>

libraryDependencies <span class="token operator">+=</span> <span class="token string">"net.walend.disentangle"</span> <span class="token operator">%</span><span class="token operator">%</span> <span class="token string">"graph"</span> <span class="token operator">%</span> <span class="token string">"0.2.0-SNAPSHOT"</span></code></pre>
<h2 id="scalas-parallel-collections">Scala's Parallel Collections</h2>
<p>Scala 2.9 provided <a href="http://docs.scala-lang.org/overviews/parallel-collections/overview.html">parallel versions of many of its standard collection classes</a>. Functional operations on these collections happen in parallel using a default compute pool. Dijkstra's and Brandes' algorithms can be run in parallel for each node. Aleksandar Prokopec provided some encouraging advice - all I needed to do was run the outermost functional operations on a parallel collection of nodes to use all the cores available.</p>
<h2 id="fifteen-minutes-later">Fifteen Minutes Later</h2>
<p>I needed about ten minutes for the first pass, and five for a second pass (<a href="http://dl.acm.org/citation.cfm?id=2442521">Brandes' algorithm has an extra wrinkle</a>) to get the algorithms running in parallel. Here's a code fragment from Dijkstra's algorithm:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">def</span> parAllPairsLeastPaths<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>EdgeLabel<span class="token punctuation">,</span>Label<span class="token punctuation">,</span>Key<span class="token punctuation">]</span><span class="token punctuation">(</span>edges<span class="token operator">:</span> GenTraversable<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> EdgeLabel<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
                                                    support<span class="token operator">:</span> SemiringSupport<span class="token punctuation">[</span>Label<span class="token punctuation">,</span> Key<span class="token punctuation">]</span><span class="token punctuation">,</span>
                                                    labelForEdge<span class="token operator">:</span> <span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> EdgeLabel<span class="token punctuation">)</span> <span class="token keyword">=></span> Label<span class="token punctuation">,</span>
                                                    nodeOrder<span class="token operator">:</span> GenSeq<span class="token punctuation">[</span>Node<span class="token punctuation">]</span> <span class="token operator">=</span> ParSeq<span class="token punctuation">.</span>empty<span class="token punctuation">)</span><span class="token operator">:</span>ParSeq<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span> Node<span class="token punctuation">,</span> Label<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token keyword">val</span> labelDigraph <span class="token operator">=</span> createLabelDigraph<span class="token punctuation">(</span>edges<span class="token punctuation">.</span>par<span class="token punctuation">,</span> support<span class="token punctuation">,</span> labelForEdge<span class="token punctuation">,</span> nodeOrder<span class="token punctuation">.</span>par<span class="token punctuation">)</span>

  <span class="token comment">//profiler blames both flatten and fold of IndexedSet as trouble</span>
  labelDigraph<span class="token punctuation">.</span>innerNodes<span class="token punctuation">.</span>to<span class="token punctuation">[</span>ParSeq<span class="token punctuation">]</span><span class="token punctuation">.</span>flatMap<span class="token punctuation">(</span>source <span class="token keyword">=></span> dijkstraSingleSource<span class="token punctuation">(</span>labelDigraph<span class="token punctuation">,</span> support<span class="token punctuation">)</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p>Making the edges collection parallel speeds up translating to the internal directed graph representation. The bigger benefit, running dijkstraSingleSource for each node in parallel, comes from putting the nodes in a parallel collection. This code was so straight-forward that I wrote it while bouncing on the T on my way home from work.</p>
<h2 id="results-on-an-aws-ec2-r38xlarge">Results on an AWS EC2 r3.8xlarge</h2>
<p>I spun up an AWS EC2 r3.8xlarge instance to benchmark on a quiet, modern, multicore computer with a quarter-terabyte of ram. Running the benchmarks was easy. I spent most of my developer time tweaking these performance graphs in D3.</p>
<div id="linearDijkstra" align="center"></div>
<script type="text/javascript">
plot3Results(false,"#linearDijkstra","../../../disentangleParGraphs/results/dijkstra.csv","../../../disentangleParGraphs/results/parDijkstra.csv","../../../disentangleParGraphs/results/floydWarshall.csv")
</script>
<p>The right half of this graph shows deviation from correct curves for Dijkstra's algorithm after about 4096 nodes. I think that's the garbage collector coming into play. (Lower is faster.) The r3.8xlarge let me use 238 GB for the JVM, which ran Dijkstra's algorithm on graphs with 16384 nodes before crashing into an out-of-memory error. I was expecting the parallel version of the algorithm to fill up memory faster than the serial version, but was pleasantly surprised that they ran out of memory on the same-sized graph. The parallel version found shortest paths for 16384 nodes in just over 15 minutes, about a 6X speedup over the serial version.</p>
<p>(You'll notice the curve for the Floyd-Warshall algorithm arcing up quickly from the lower left. The Floyd-Warshall test didn't crash; I had a spare half-hour of compute time after one of the larger tests and stopped it after that.)</p>
<div id="logDijkstra" align="center"></div>
<script type="text/javascript">
plot3Results(true,"#logDijkstra","../../../disentangleParGraphs/results/dijkstra.csv","../../../disentangleParGraphs/results/parDijkstra.csv","../../../disentangleParGraphs/results/floydWarshall.csv")
</script>
<p>To examine what was happening in that lower left corner I plotted the results log/log. (A little lower is much faster.) As you can see, the crossover point where concurrency starts to pay off seems to be at about 90 nodes (on a quiet AWS r3.8xlarge with 32 cores and 244 GB ram - YMMV). The Floyd-Warshall algorithm was never better for graphs with 32 or more nodes.</p>
<p>I found similar results for Brandes algorithm.</p>
<div id="linearBrandes" align="center"></div>
<script type="text/javascript">
plot2Results(false,"#linearBrandes","../../../disentangleParGraphs/results/brandes.csv","../../../disentangleParGraphs/results/parBrandes.csv")
</script>
<div id="logBrandes" align="center"></div>
<script type="text/javascript">
plot2Results(true,"#logBrandes","../../../disentangleParGraphs/results/brandes.csv","../../../disentangleParGraphs/results/parBrandes.csv")
</script>
<p>You can see some inefficiency - maybe the JVM garbage collector - start to come into play after about 4096 nodes, but it was able to find all shortest paths and betweenness for every node in just over 15 minutes for 16384 nodes on an EC2 r3.8xlarge. That's about a 6X speed-up over non-parallel. Not bad for 15 minutes of effort with no regard for <a href="https://en.wikipedia.org/wiki/Amdahl%27s_law">Amdahl's law</a>.</p>
<h2 id="try-it-out">Try it out</h2>
<p>Pull it into an sbt project via</p>
<pre class="language-scala"><code class="language-scala">resolvers <span class="token operator">+=</span> <span class="token string">"Sonatype OSS Snapshots"</span> at <span class="token string">"https://oss.sonatype.org/content/repositories/snapshots"</span>

libraryDependencies <span class="token operator">+=</span> <span class="token string">"net.walend.disentangle"</span> <span class="token operator">%</span><span class="token operator">%</span> <span class="token string">"graph"</span> <span class="token operator">%</span> <span class="token string">"0.2.0-SNAPSHOT"</span></code></pre>
<p>Or clone the project and play in the console</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/dwalend/Disentangle.git
<span class="token builtin class-name">cd</span> Disentangle
sbt console</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Renaming to Disentangle</title>
      <link>https://blog.walend.net/2015/11/Rename-to-Disentangle/</link>
      <guid isPermaLink="true">https://blog.walend.net/2015/11/Rename-to-Disentangle/</guid>
      <pubDate>Tue, 03 Nov 2015 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <description>I renamed ScalaGraphMinimizer to Disentangle.</description>
      <content:encoded><![CDATA[<p>TL/DR - I renamed ScalaGraphMinimizer to <a href="https://github.com/dwalend/Disentangle">Disentangle</a>, which better matches what the library is about. Pull in the latest snapshot with</p>
<pre class="language-scala"><code class="language-scala">resolvers <span class="token operator">+=</span> <span class="token string">"Sonatype OSS Snapshots"</span> at <span class="token string">"https://oss.sonatype.org/content/repositories/snapshots"</span>

libraryDependencies <span class="token operator">+=</span> <span class="token string">"net.walend.disentangle"</span> <span class="token operator">%</span><span class="token operator">%</span> <span class="token string">"graph"</span> <span class="token operator">%</span> <span class="token string">"0.2.0-SNAPSHOT"</span></code></pre>
<h2 id="disentangle">Disentangle</h2>
<p>I renamed ScalaGraphMinimizer to <a href="https://github.com/dwalend/Disentangle">Disentangle</a>. I wanted to change the name for a while. ScalaGraphMinimizer is internet-unique, but was nearly impossible to say using a human mouth. My work with semiring-based minimization algorithms is mature at this point and I'd like project to grow in new directions. While working on parallel versions of algorithms this fall I realized ScalaGraphMinimizer was about to outgrow its name.</p>
<p>I picked the name Disentangle to provide a double-meaning of optimism of purpose and guidance for the code.</p>
<p>On its surface, Disentangle is a library of algorithms to help provide human insight for complex graph structures. In my day job too often I've projected a picture of a hairball of a graph on a screen in a dark room, narrating it with words like, &quot;This graph is really complicated, but - next slide please - I found these interesting things that you may care about.&quot; Disentangle has already helped tell some stories and I plan to keep grown the library in that theme.</p>
<p>The second meaning is guidance for me creating the library and a promise to people using it. I want Disentangle to be a non-invasive library used via a few clean method calls, not a project-defining framework. It uses some of Scala's common-currency parts - collections and tuples - as the core of Disentangle's API. Specifically it does not provide a domain-specific language or require developers to extend its internal structures.</p>
<p>The above differentiates Disentangle from its predecessors. Some structures, like lists, sets, and maps, are ubiquitous, almost universal, and having them in a common core library makes sense. Other structures like a <a href="https://java.net/projects/somnifugijms/sources/svn/content/trunk/source/somnifugi/net/walend/somnifugi/juc/MessageSelectingPriorityBlockingQueue.java?rev=287">master-and-servant set of queues of AtomicMarkedReferences</a> are purpose-built for their specialized tasks. Graphs fall in a gap between these extremes because graphs have <a href="https://en.wikipedia.org/wiki/Graph_(mathematics)">a lot of lot of commonality and a lot of variation.</a> Other graph frameworks require developers to begin by supplying graphs defined in that framework's structures. Developers who attempt to use those frameworks frequently give up when the framework doesn't meet their needs. They rip out the first attempt (or - far worse - leave it in to gum up the works) and replace it with custom one-use code. I hope that happens less with Disentangle.</p>
<h2 id="graphs-collections-and-tuples">Graphs, Collections, and Tuples</h2>
<p>Computer languages are usually pretty good at defining graphs, at least directed graphs. A general-purpose programming language ought to provide a good starting point for general-purpose graph algorithms without demanding too much from developers. Scala - as a better Java - provides a lot of easily-accessible features through its type system. I chose those features for Disentangle's surface API. Disentangle's starting point is a collection of Tuples and a simple, single API call on an object. Code that uses it looks like this:</p>
<pre class="language-scala"><code class="language-scala"><span class="token comment">/**
 * Edges are just a Seq of Tuple3[Node,Node,Edge]
 */</span>
<span class="token keyword">val</span> edges<span class="token operator">:</span> Seq<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> Seq<span class="token punctuation">(</span>
                                              <span class="token punctuation">(</span><span class="token string">"A"</span><span class="token punctuation">,</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"ab"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"bc"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"D"</span><span class="token punctuation">,</span><span class="token string">"cd"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"D"</span><span class="token punctuation">,</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"de"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"F"</span><span class="token punctuation">,</span><span class="token string">"ef"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"B"</span><span class="token punctuation">,</span><span class="token string">"eb"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"E"</span><span class="token punctuation">,</span><span class="token string">"H"</span><span class="token punctuation">,</span><span class="token string">"eh"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                              <span class="token punctuation">(</span><span class="token string">"H"</span><span class="token punctuation">,</span><span class="token string">"C"</span><span class="token punctuation">,</span><span class="token string">"hc"</span><span class="token punctuation">)</span>
                                            <span class="token punctuation">)</span>

<span class="token keyword">import</span> <span class="token namespace">net<span class="token punctuation">.</span>walend<span class="token punctuation">.</span>disentangle<span class="token punctuation">.</span>graph<span class="token punctuation">.</span>semiring<span class="token punctuation">.</span></span><span class="token punctuation">{</span>Dijkstra<span class="token punctuation">,</span>FirstStepsTrait<span class="token punctuation">}</span>

<span class="token comment">/**
 * Generate all the shortest paths in the graph
 */</span>
<span class="token keyword">val</span> simpleShortPathLabels <span class="token operator">=</span> Dijkstra<span class="token punctuation">.</span>allPairsShortestPaths<span class="token punctuation">(</span>edges<span class="token punctuation">)</span></code></pre>
<p>or with types defined:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">val</span> simpleShortPathLabels<span class="token operator">:</span> Seq<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">,</span> Option<span class="token punctuation">[</span>FirstStepsTrait<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">Int</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> 
    Dijkstra<span class="token punctuation">.</span>allPairsShortestPaths<span class="token punctuation">(</span>edges<span class="token punctuation">)</span></code></pre>
<p>FirstStepsTrait has a Set of possible first steps to take on shortest paths, and the length of those paths.</p>
<h2 id="semirings-inside">Semirings Inside</h2>
<p>Other frameworks get into trouble when you want something just a little beyond exactly what their algorithms can deliver. To customize the code you have to fork and bend the whole algorithm. However, Disentangle's implementations of the Floyd-Warshall algorithm, Dijkstra's algorithm, and Brandes' algorithm take a semiring to define what &quot;shortest path&quot; means. Dijkstra.allPairsShortestPaths() is a wrapper method around allPairsLeastPaths(), which takes a SemiringSupport object. The default version finds paths with the fewest nodes. Here's a code snippet from inside of object Dijkstra:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">def</span> defaultSupport<span class="token punctuation">[</span>Node<span class="token punctuation">]</span> <span class="token operator">=</span> AllPathsFirstSteps<span class="token punctuation">[</span>Node<span class="token punctuation">,</span><span class="token builtin">Int</span><span class="token punctuation">,</span><span class="token builtin">Int</span><span class="token punctuation">]</span><span class="token punctuation">(</span>FewestNodes<span class="token punctuation">)</span>

<span class="token keyword">def</span> allPairsShortestPaths<span class="token punctuation">[</span>Node<span class="token punctuation">,</span>EdgeLabel<span class="token punctuation">]</span><span class="token punctuation">(</span>edges<span class="token operator">:</span>GenTraversable<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span>Node<span class="token punctuation">,</span>EdgeLabel<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
                                      nodeOrder<span class="token operator">:</span>GenSeq<span class="token punctuation">[</span>Node<span class="token punctuation">]</span> <span class="token operator">=</span> Seq<span class="token punctuation">.</span>empty
                                    <span class="token punctuation">)</span><span class="token operator">:</span>Seq<span class="token punctuation">[</span><span class="token punctuation">(</span>Node<span class="token punctuation">,</span>Node<span class="token punctuation">,</span>Option<span class="token punctuation">[</span>FirstStepsTrait<span class="token punctuation">[</span>Node<span class="token punctuation">,</span> <span class="token builtin">Int</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token keyword">val</span> support <span class="token operator">=</span> defaultSupport<span class="token punctuation">[</span>Node<span class="token punctuation">]</span>
  allPairsLeastPaths<span class="token punctuation">(</span>edges<span class="token punctuation">,</span> support<span class="token punctuation">,</span> support<span class="token punctuation">.</span>convertEdgeToLabel<span class="token punctuation">(</span>FewestNodes<span class="token punctuation">.</span>convertEdgeToLabel<span class="token punctuation">)</span><span class="token punctuation">,</span> nodeOrder<span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="pick-weights-via-semirings">Pick Weights via Semirings</h2>
<p>My most specific complaint with other frameworks is their baked-in selection of what to use for weights. Disentangle is semiring-based, so you can supply the semiring -- you can use a weight that matches your needs. I created a straight-forward double-based semiring - LeastWeights - to provide traditional Double weights. It's easy to <a href="https://github.com/dwalend/Disentangle/blob/to0.1.2/graph/src/main/scala/net/walend/disentangle/graph/semiring/LeastWeights.scala">copy and bend to your needs</a>.</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">import</span> <span class="token namespace">net<span class="token punctuation">.</span>walend<span class="token punctuation">.</span>disentangle<span class="token punctuation">.</span>graph<span class="token punctuation">.</span>semiring<span class="token punctuation">.</span></span><span class="token punctuation">{</span>AllPathsFirstSteps<span class="token punctuation">,</span>LeastWeights<span class="token punctuation">}</span>
<span class="token keyword">val</span> support<span class="token operator">:</span> AllPathsFirstSteps<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">Double</span><span class="token punctuation">,</span> <span class="token builtin">Double</span><span class="token punctuation">]</span> <span class="token operator">=</span> 
  <span class="token keyword">new</span> AllPathsFirstSteps<span class="token punctuation">(</span>LeastWeights<span class="token punctuation">)</span></code></pre>
<p>(If the edges aren't Doubles already you'll need to supply some function to convert your edges to Doubles. I wrote this cheezy hack as an example.)</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">def</span> stringToDouble<span class="token punctuation">(</span>fromNode<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>toNode<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>edge<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token builtin">Double</span> <span class="token operator">=</span> 
  edge<span class="token punctuation">.</span>map<span class="token punctuation">(</span>_<span class="token punctuation">.</span>hashCode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>toDouble<span class="token punctuation">)</span><span class="token punctuation">.</span>product</code></pre>
<p>Instead of calling allPairsShortestPaths() call allPairsLeastPaths() to generate all the shortest paths.</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">val</span> leastPathLabels<span class="token operator">:</span> Seq<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token builtin">String</span><span class="token punctuation">,</span> <span class="token builtin">String</span><span class="token punctuation">,</span> support<span class="token punctuation">.</span>Label<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> 
  Dijkstra<span class="token punctuation">.</span>allPairsLeastPaths<span class="token punctuation">(</span>edges<span class="token punctuation">,</span>support<span class="token punctuation">,</span>support<span class="token punctuation">.</span>convertEdgeToLabel<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">]</span><span class="token punctuation">(</span>stringToDouble<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<h2 id="other-semirings">Other Semirings</h2>
<p>Because Disentangle is semiring-based, it's possible to create your own semirings have standard algorithms solve for something other than a &quot;least path.&quot; For example, here's one for <a href="https://github.com/dwalend/Disentangle/blob/to0.1.2/graph/src/main/scala/net/walend/disentangle/graph/semiring/MostProbable.scala">most probable paths</a>.</p>
<h2 id="try-it-out">Try it out</h2>
<p>Pull it into an sbt project via</p>
<pre class="language-scala"><code class="language-scala">resolvers <span class="token operator">+=</span> <span class="token string">"Sonatype OSS Snapshots"</span> at <span class="token string">"https://oss.sonatype.org/content/repositories/snapshots"</span>

libraryDependencies <span class="token operator">+=</span> <span class="token string">"net.walend.disentangle"</span> <span class="token operator">%</span><span class="token operator">%</span> <span class="token string">"graph"</span> <span class="token operator">%</span> <span class="token string">"0.2.0-SNAPSHOT"</span></code></pre>
<p>Or clone the project and play in the console</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/dwalend/Disentangle.git
<span class="token builtin class-name">cd</span> Disentangle
sbt console</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Testing With TypeSafe Config</title>
      <link>https://blog.walend.net/2015/06/Test-With-TypeSafeConfig/</link>
      <guid isPermaLink="true">https://blog.walend.net/2015/06/Test-With-TypeSafeConfig/</guid>
      <pubDate>Sun, 21 Jun 2015 00:00:00 +0000</pubDate>
      <dc:creator>David Walend</dc:creator>
      <description>I found a workable compromise for testing with different configurations using TypeSafe Config without starting a new JVM or turning the code inside out.</description>
      <content:encoded><![CDATA[<h1 id="testing-with-typesafe-config">Testing With TypeSafe Config</h1>
<p>TL/DR - I found a workable compromise for testing with different configurations using <a href="https://github.com/typesafehub/config">typesafe config</a> without starting a new JVM or turning the code inside out. See this <a href="https://gist.github.com/dwalend/5a193daa24af8dbfbdc5">gist</a>.</p>
<h2 id="simple-structures">Simple Structures</h2>
<p>TypeSafe Config code loads the config from a hierarchy of sources - primarily files on the classpath and java.lang.System properties. I can access my system's configuration from anywhere by calling</p>
<pre class="language-scala"><code class="language-scala">  <span class="token keyword">val</span> config <span class="token operator">=</span> ConfigFactory<span class="token punctuation">.</span>load<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">val</span> dbUrl <span class="token operator">=</span> config<span class="token punctuation">.</span>getString<span class="token punctuation">(</span><span class="token string">"database.url"</span><span class="token punctuation">)</span></code></pre>
<p>I want to keep that simplicity. However, I also needed a good way to test with different configurations. My day-job project, <a href="http://catalyst.harvard.edu/services/shrine/">Shrine</a>'s Data Steward Web App, has three different major configurations, maybe a dozen variations.</p>
<p>Specifically, I want the code to use simple structures that pull their configurations from a typesafe <a href="https://github.com/typesafehub/config/blob/master/config/src/main/java/com/typesafe/config/Config.java">Config</a> object. I want to be able to replicate the technique shamelessly without sharing code between subprojects. Further, I do not want that Config exposed in my system's Scala API; I should be able to use Scala's singleton [<code>object</code>s] (https://raseshmori.wordpress.com/2013/06/20/scala-part-4-classes-objects/) where I need singletons. At the day job, the configuration is unchanging once set - except for during tests. Having it front-and-center distracts from more important details. I should not have to couple my code via constructor parameters that make me wish for an aspect-oriented style. After all it's just config.</p>
<h2 id="three-compromises">Three Compromises</h2>
<p>I thought of three options. None are perfect, but one is good enough.</p>
<h3 id="start-a-new-process">Start a New Process</h3>
<p>The most brute force approach is to use a different JVM process for testing each configuration. That's how I'd have handled this back in the age of <a href="http://zeroturnaround.com/rebellabs/java-build-tools-part-2-a-decision-makers-comparison-of-maven-gradle-and-ant-ivy/">ant</a>. However, Shrine uses maven. Creating a new JVM process for tests is out-of-model in Shrine and possibly in any maven project. I skipped from ant to <a href="https://codeascraft.com/2014/09/30/building-a-better-build-our-transition-from-ant-to-sbt/">sbt</a>. During the age of maven I was at MathWorks where we used make. Maven feels as alien as a <a href="https://www.etsy.com/listing/91486506/alien-hand-knit-kiwi-green-warm-three">three-fingered glove</a> to me. I don't know a tasteful way to spin up several new processes for running tests in the same maven subproject.</p>
<h3 id="config-parameter-objects">Config Parameter Objects</h3>
<p>The older code in Shrine uses config parameter objects, skipping typesafe config, to test parts of the system in isolation. A maven subproject uses typesafe config to drive various abstract-factory-pattern-inspired parts to construct parts for Shrine. Testing different configurations means constructing specialized configuration helpers instead of using a simple Config. The approach definitely solves the problem, but it adds a long, twisty maze between the config files where a value is defined and the code that actually uses it. Following that path adds about five minutes to each task involving a config key-value pair. The approach seems particularly invasive because singletons that could have been Scala <code>object</code>s have to be constructed class instances. The existing pattern tightly couples the Shrine system around a single instance of a ShrineConfig class to keep the whole works from becoming a furball. Testing more than a single subsystem is very difficult. I found myself repeating my criticisms of Spring mixed with profane mutterings about <a href="http://perl.plover.com/yak/design/samples/slide004.html">GLOOP</a>. Someday I want to clean up that part of the code, not add to the confusion.</p>
<h3 id="higher-order-config-hack">Higher-Order Config Hack</h3>
<p>I decided to wrap typesafe config with just a little mutability and use <a href="http://blog.jessitron.com/2012/07/choices-with-def-and-val-in-scala.html">defs</a> where I need configurable values. Using defs for configurable values forces them to be reevaluated each time the owning code accesses them; there will always be a little in-memory overhead. However, any part of the system can access the Config when needed, with a key's name right next to the def that supplies the value.</p>
<pre class="language-scala"><code class="language-scala">  <span class="token keyword">def</span> dbUrl <span class="token operator">=</span> ExampleConfigSource<span class="token punctuation">.</span>config<span class="token punctuation">.</span>getString<span class="token punctuation">(</span><span class="token string">"database.url"</span><span class="token punctuation">)</span></code></pre>
<p>My first hack at the solution was to set and clean up system properties in a try/finally block, and use <a href="https://github.com/typesafehub/config/blob/master/config/src/main/java/com/typesafe/config/ConfigFactory.java">ConfigFactory</a>'s resetCache method. The project is a web app showing a database; I can afford a little compute overhead, but it just seemed sloppy. I won't share some of the uglier code, but the progression to something clean went fine. The second hack was to put the try/finally into a higher-order function. The third step started to look less hacky. I replaced the cache flush and system properties with API to use <a href="https://github.com/typesafehub/config#merging-config-trees">Config's withFallback()</a> to get the default (cached and unchanging) Config. I put the changeable Config inside an <a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html">AtomicReference</a> for minimal concurrent safety. Finally I dressed it up in a Scala-style <a href="http://danielwestheide.com/blog/2012/12/26/the-neophytes-guide-to-scala-part-6-error-handling-with-try.html">Try/Success/Failure</a> . It's not fool-proof, but should be fine for running one test at a time.</p>
<p>Here's what the code looks like:</p>
<pre class="language-scala"><code class="language-scala"><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span>atomic<span class="token punctuation">.</span></span>AtomicReference
<span class="token keyword">import</span> <span class="token namespace">scala<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token punctuation">{</span>Failure<span class="token punctuation">,</span> Success<span class="token punctuation">,</span> Try<span class="token punctuation">}</span>
<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>typesafe<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span><span class="token punctuation">{</span>Config<span class="token punctuation">,</span> ConfigFactory<span class="token punctuation">}</span>

<span class="token comment">/**
 * Use to tweak a Config without clearing and reloading a new config (for testing).
 *
 * @author dwalend
 */</span>
<span class="token keyword">class</span> AtomicConfigSource<span class="token punctuation">(</span>baseConfig<span class="token operator">:</span>Config<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">val</span> atomicConfigRef <span class="token operator">=</span> <span class="token keyword">new</span> AtomicReference<span class="token punctuation">[</span>Config<span class="token punctuation">]</span><span class="token punctuation">(</span>ConfigFactory<span class="token punctuation">.</span>empty<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
 
  <span class="token comment">/**
   * Get the atomic Config. Be sure to use defs for all 
   * config values that might be changed.
   */</span>
  <span class="token keyword">def</span> config<span class="token operator">:</span>Config <span class="token operator">=</span> atomicConfigRef<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>withFallback<span class="token punctuation">(</span>baseConfig<span class="token punctuation">)</span>
 
  <span class="token comment">/**
   * Use the config in a block of code with just one key/value replaced.
   */</span>
  <span class="token keyword">def</span> configForBlock<span class="token punctuation">[</span>T<span class="token punctuation">]</span><span class="token punctuation">(</span>key<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>value<span class="token operator">:</span><span class="token builtin">AnyRef</span><span class="token punctuation">,</span>origin<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">)</span><span class="token punctuation">(</span>block<span class="token operator">:</span> <span class="token keyword">=></span> T<span class="token punctuation">)</span><span class="token operator">:</span>T <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token keyword">val</span> configPairs <span class="token operator">=</span> Map<span class="token punctuation">(</span>key <span class="token operator">-></span> value<span class="token punctuation">)</span>
    configForBlock<span class="token punctuation">(</span>configPairs<span class="token punctuation">,</span>origin<span class="token punctuation">)</span><span class="token punctuation">(</span>block<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
 
  <span class="token comment">/**
   * Use the config in a block of code.
   */</span>
  <span class="token keyword">def</span> configForBlock<span class="token punctuation">[</span>T<span class="token punctuation">]</span><span class="token punctuation">(</span>configPairs<span class="token operator">:</span>Map<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">,</span> _ <span class="token operator">&lt;</span><span class="token operator">:</span> <span class="token builtin">AnyRef</span><span class="token punctuation">]</span><span class="token punctuation">,</span>origin<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">)</span><span class="token punctuation">(</span>block<span class="token operator">:</span> <span class="token keyword">=></span> T<span class="token punctuation">)</span><span class="token operator">:</span>T <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token keyword">import</span> <span class="token namespace">scala<span class="token punctuation">.</span>collection<span class="token punctuation">.</span></span>JavaConverters<span class="token punctuation">.</span>mapAsJavaMapConverter
 
    <span class="token keyword">val</span> configPairsJava<span class="token operator">:</span>java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>Map<span class="token punctuation">[</span><span class="token builtin">String</span><span class="token punctuation">,</span> _ <span class="token operator">&lt;</span><span class="token operator">:</span> <span class="token builtin">AnyRef</span><span class="token punctuation">]</span> <span class="token operator">=</span> configPairs<span class="token punctuation">.</span>asJava
    <span class="token keyword">val</span> blockConfig<span class="token operator">:</span>Config <span class="token operator">=</span> ConfigFactory<span class="token punctuation">.</span>parseMap<span class="token punctuation">(</span>configPairsJava<span class="token punctuation">,</span>origin<span class="token punctuation">)</span>
    <span class="token keyword">val</span> originalConfig<span class="token operator">:</span>Config <span class="token operator">=</span> atomicConfigRef<span class="token punctuation">.</span>getAndSet<span class="token punctuation">(</span>blockConfig<span class="token punctuation">)</span>
    <span class="token keyword">val</span> tryT<span class="token operator">:</span>Try<span class="token punctuation">[</span>T<span class="token punctuation">]</span> <span class="token operator">=</span> Try<span class="token punctuation">(</span>block<span class="token punctuation">)</span>
 
    <span class="token keyword">val</span> ok <span class="token operator">=</span> atomicConfigRef<span class="token punctuation">.</span>compareAndSet<span class="token punctuation">(</span>blockConfig<span class="token punctuation">,</span>originalConfig<span class="token punctuation">)</span>
 
    tryT <span class="token keyword">match</span> <span class="token punctuation">{</span>
      <span class="token keyword">case</span> Success<span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token keyword">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>ok<span class="token punctuation">)</span> t
        <span class="token keyword">else</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> IllegalStateException<span class="token punctuation">(</span>
          <span class="token string-interpolation"><span class="token id function">s</span><span class="token string">"Expected config from </span><span class="token interpolation"><span class="token punctuation">${</span><span class="token expression">blockConfig<span class="token punctuation">.</span>origin<span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> to be from </span><span class="token interpolation"><span class="token punctuation">${</span><span class="token expression">atomicConfigRef<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>origin<span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> instead."</span></span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">case</span> Failure<span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token keyword">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>ok<span class="token punctuation">)</span> <span class="token keyword">throw</span> x
        <span class="token keyword">else</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> IllegalStateException<span class="token punctuation">(</span>
          <span class="token string-interpolation"><span class="token id function">s</span><span class="token string">"Throwable in block and expected config from </span><span class="token interpolation"><span class="token punctuation">${</span><span class="token expression">blockConfig<span class="token punctuation">.</span>origin<span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> to be from </span><span class="token interpolation"><span class="token punctuation">${</span><span class="token expression">atomicConfigRef<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>origin<span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> instead."</span></span><span class="token punctuation">,</span>x<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>To use it, I create a Scala object to hold the config:</p>
<pre class="language-scala"><code class="language-scala"><span class="token comment">/**
 * A little object to let you reach your config from anywhere.
 * 
 * @author dwalend
 */</span>
<span class="token keyword">object</span> ExampleConfigSource <span class="token punctuation">{</span>
  <span class="token comment">//load from application.conf and the usual typesafe config sources</span>
  <span class="token keyword">val</span> atomicConfig <span class="token operator">=</span> <span class="token keyword">new</span> AtomicConfigSource<span class="token punctuation">(</span>ConfigFactory<span class="token punctuation">.</span>load<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> 
 
  <span class="token keyword">def</span> config<span class="token operator">:</span>Config <span class="token operator">=</span> atomicConfig<span class="token punctuation">.</span>config
 
  <span class="token keyword">def</span> configForBlock<span class="token punctuation">[</span>T<span class="token punctuation">]</span><span class="token punctuation">(</span>key<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">,</span>value<span class="token operator">:</span><span class="token builtin">AnyRef</span><span class="token punctuation">,</span>origin<span class="token operator">:</span><span class="token builtin">String</span><span class="token punctuation">)</span><span class="token punctuation">(</span>block<span class="token operator">:</span> <span class="token keyword">=></span> T<span class="token punctuation">)</span><span class="token operator">:</span>T <span class="token operator">=</span> 
    atomicConfig<span class="token punctuation">.</span>configForBlock<span class="token punctuation">(</span>key<span class="token punctuation">,</span>value<span class="token punctuation">,</span>origin<span class="token punctuation">)</span><span class="token punctuation">(</span>block<span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p>To change config in a test, wrap the test code in a configForBlock:</p>
<pre class="language-scala"><code class="language-scala">  <span class="token string">"Steward"</span> should <span class="token string">" accept query requests with no topic in 'just log and approve everything' mode "</span> in <span class="token punctuation">{</span>

    ExampleConfigSource<span class="token punctuation">.</span>configForBlock<span class="token punctuation">(</span><span class="token string">"shrine.steward.createTopicsMode"</span><span class="token punctuation">,</span> 
                                        CreateTopicsMode<span class="token punctuation">.</span>TopicsIgnoredJustLog<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">{</span>

      Post<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token id function">s</span><span class="token string">"/qep/requestQueryAccess/user/</span><span class="token interpolation"><span class="token punctuation">${</span><span class="token expression">researcherUserName</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span>InboundShrineQuery<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token string">"test query"</span><span class="token punctuation">,</span><span class="token string">"Not even using a topic"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">~</span><span class="token operator">></span>
        addCredentials<span class="token punctuation">(</span>qepCredentials<span class="token punctuation">)</span> <span class="token operator">~</span><span class="token operator">></span>
        route <span class="token operator">~</span><span class="token operator">></span> check <span class="token punctuation">{</span>
        assertResult<span class="token punctuation">(</span>OK<span class="token punctuation">)</span><span class="token punctuation">(</span>status<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
]]></content:encoded>
    </item>
  </channel>
</rss>
