<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:blog.keithrowell.com,2005:/feed</id>
  <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/"/>
  <link rel="self" type="application/atom+xml" href="https://blog.keithrowell.com/feed"/>
  <title>Keith Rowell</title>
  <subtitle>Software, design, Formula 1, photography, wine, and life.</subtitle>
  <updated>2026-10-03T20:00:00+10:00</updated>
  <author>
    <name>Keith Rowell</name>
  </author>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/28</id>
    <published>2026-10-03T20:00:00+10:00</published>
    <updated>2026-10-03T23:54:21+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/28-the-two-worlds-of-wine"/>
    <title>The Two Worlds of Wine</title>
    <content type="html">&lt;p&gt;I was out to dinner a while back and watched someone pick up the wine list, skip the whites entirely and start reading at the reds. Not a decision – a reflex. It&amp;#8217;s a common one.&lt;/p&gt;

&lt;p&gt;I drink both, happily, and this isn&amp;#8217;t a case for one over the other. But if you asked me which of the two has more going on – more moving parts, more detail to get lost in – I&amp;#8217;d say whites, and I wouldn&amp;#8217;t need long to think about it.&lt;/p&gt;

&lt;p&gt;Reds have the prestige, and they&amp;#8217;ve earned a lot of it. The collectible bottles, the vintages people argue about for decades, the terroir mythology, the cellar – that&amp;#8217;s mostly red territory. If wine is a status game or an investment, reds win and it isn&amp;#8217;t close.&lt;/p&gt;

&lt;p&gt;But prestige and range are different things. Reds vary along a short list of axes: tannins, oak, fruit. The gap between a Pinot Noir, a Nebbiolo and a Cabernet is real and worth caring about, but it comes down to those three dials, and everything routes back through tannin.&lt;/p&gt;

&lt;p&gt;Whites have more dials, and the dials turn independently. Acidity, sweetness, weight and aroma each do their own thing. You can run from bone-dry and mineral – a Chablis, or an Assyrtiko that tastes of salt and stone – through the lush, oaked weight of a white Burgundy, out to an off-dry Riesling or a Gewürztraminer that&amp;#8217;s all lychee and rosewater, and then keep going into skin-contact &amp;#8220;orange&amp;#8221; wine, which sits on its skins like a red and comes out with actual tannin and grip. That&amp;#8217;s an enormous spread, and at no point does tannin have to be the thing doing the talking.&lt;/p&gt;

&lt;p&gt;I wanted to be sure this wasn&amp;#8217;t just my palate talking, so I checked. A while back I built a wine app, &lt;a href="https://ampelos.keithrowell.com"&gt;Ampelos&lt;/a&gt;, with a taxonomy of a hundred-odd grape varieties, each scored for body, tannin, acidity, sweetness and aromatic intensity, with its flavour descriptors and the aroma compounds behind them. The split is almost even – 57 whites, 52 reds. The shape of the data is the interesting bit. In the reds, body and tannin move together so closely they may as well be one dial, sweetness is pinned at dry, and aromatic intensity sits at &amp;#8220;medium&amp;#8221; for most of them. The variation is nearly all structure. In the whites, tannin is the thing that&amp;#8217;s pinned and everything else is loose: acidity and aroma spread right across their range, sweetness runs from bone-dry to dessert, and apart from the sweet ones tending to be the perfumed ones, none of it tracks anything else. Count the distinct combinations of those three and the whites produce two and a half times as many as the reds, from roughly the same number of grapes.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s what that looks like for a single white. This is Heritage Estate&amp;#8217;s Fumé Marsanne from the Granite Belt – a barrel-fermented Marsanne – run through the app, which separates what the grape brings from what the place and the winemaking added:&lt;/p&gt;

&lt;figure&gt;
&lt;img src="/blog/articles/the_two_worlds_of_wine.md.images/heritage-profile.png" alt="Ampelos analysis of Heritage Estate Fumé Marsanne 2022 – what the grape brings, what the other layers added, and the chemistry in the glass" /&gt;
&lt;figcaption&gt;Ampelos analysis of Heritage Estate Fumé Marsanne 2022 – what the grape brings, what the other layers added, and the chemistry in the glass&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You can also see the winemaking. Virtually every red goes through malolactic conversion; in a white it&amp;#8217;s a choice, and you can taste which way it went. Stirring the lees, oxidative handling versus reductive – in a white these show up as texture and smell you can point at: butter, brioche, bruised apple, struck match. That same taxonomy has a whole flavour category for fermentation and lees character, and not a single red grape touches it. In a red the same techniques get folded into &amp;#8220;how much oak, how much tannin, how ripe,&amp;#8221; which flattens the differences. Both get to an answer. A white shows its working on the way there, and that&amp;#8217;s where the riches are. A red hands you the answer with the working rubbed out.&lt;/p&gt;

&lt;p&gt;The same Marsanne, layer by layer. Seven of the grape&amp;#8217;s own notes, then terroir, vineyard, ferment and élevage each adding their own – and the honeysuckle and quince the grape would normally offer, sitting quiet under the oak. That&amp;#8217;s the working:&lt;/p&gt;

&lt;figure&gt;
&lt;img src="/blog/articles/the_two_worlds_of_wine.md.images/heritage-layers.png" alt="The same wine broken down by layer – variety, terroir, vineyard and vintage, ferment, élevage" /&gt;
&lt;figcaption&gt;The same wine broken down by layer – variety, terroir, vineyard and vintage, ferment, élevage&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Reds do have territory of their own – pepper and spice, earth, the long slide into leather and truffle with age – and I&amp;#8217;m not pretending otherwise. It&amp;#8217;s just a smaller territory than the reputation suggests.&lt;/p&gt;

&lt;p&gt;If you want the whole argument in one glass, find a Shiraz with a few percent of Viognier in it – two to five, co-fermented, the way they&amp;#8217;ve always done it in Côte-Rôtie and the way Clonakilla has done it in Canberra for decades. It&amp;#8217;s a trivial amount of white grape. The wine is not trivially different: the perfume lifts, there&amp;#8217;s apricot and florals over the dark fruit, the texture goes silky, and it is plainly not a straight Shiraz. Five percent of white, and the red is a different wine. That&amp;#8217;s how much is packed into the white side.&lt;/p&gt;

&lt;p&gt;None of this is theoretical, either. The most interesting experimental work in Australian boutique wine right now is on the white side – skin-contact Semillon out of the Barossa, wild-ferment Riesling, aromatic blends nobody&amp;#8217;s bothering to attempt with reds. The energy is in the whites.&lt;/p&gt;

&lt;p&gt;So keep buying the reds. Argue about the vintages, lay them down, pay too much for the good ones – all of that is genuinely fun and I do it too. Just don&amp;#8217;t skip past the whites on the way. And don&amp;#8217;t reach for the one you already know, either – the New Zealand Sauvignon Blanc is the same reflex in white. Go to a decent wine shop and ask for something off the usual list: a Roussanne or a Marsanne, a Viognier, a Chenin Blanc, an Alsace Gewürztraminer, a Fiano, an Assyrtiko, a Grüner Veltliner, a Hunter Semillon with ten years on it. That&amp;#8217;s the other world, and it&amp;#8217;s the bigger one.&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/31</id>
    <published>2026-01-08T07:39:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/31-a-year-with-a-camera-2025"/>
    <title>A Year With a Camera 2025</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2025 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2025.md.images/2025_a_year_with_a_camera.mp4" title="A Year With a Camera 2025"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2025.md.images/a_year_with_a_camera_2025.png" alt="A Year With a Camera 2025" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/30</id>
    <published>2025-01-08T07:47:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/30-a-year-with-a-camera-2024"/>
    <title>A Year With a Camera 2024</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2024 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2024.md.images/2024_a_year_with_a_camera.mp4" title="A Year With a Camera 2024"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2024.md.images/a_year_with_a_camera_2024.png" alt="A Year With a Camera 2024" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/29</id>
    <published>2024-01-09T02:36:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/29-a-year-with-a-camera-2023"/>
    <title>A Year With a Camera 2023</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2023 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2023.md.images/2023_a_year_with_a_camera.mp4" title="A Year With a Camera 2023"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2023.md.images/a_year_with_a_camera_2023.png" alt="A Year With a Camera 2023" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/5</id>
    <published>2023-01-03T00:30:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/5-a-year-with-a-camera-2022"/>
    <title>A Year With a Camera 2022</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2022 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2022.md.images/2022_a_year_with_a_camera.mp4" title="A Year With a Camera 2022"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2022.md.images/a_year_with_a_camera_2022.png" alt="A Year With a Camera 2022" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/6</id>
    <published>2022-03-26T02:00:00+10:00</published>
    <updated>2026-10-04T09:18:13+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/6-adding-map-style-switching-to-mapbox-using-matestack"/>
    <title>Adding Map Style Switching to Mapbox using Matestack</title>
    <content type="html">&lt;p&gt;When providing map services to clients in a mapping application, it’s quite normal for them to want to have the option to view the geospatial data on different map styles. Views such as dark, light, transit, satellite, etc.&lt;/p&gt;

&lt;p&gt;A couple of says ago, I saw some developers do this on a &lt;a href="https://reactjs.org"&gt;React&lt;/a&gt; project and I was shocked at how much code was required and how complex it was. Literally shocked. The changset listed in the git commit spanned a good number of pages.&lt;/p&gt;

&lt;p&gt;That evening I added this very functionality to a mapping app that I maintain. The app was built with &lt;a href="https://rubyonrails.org"&gt;Rails 6&lt;/a&gt; and &lt;a href="https://docs.matestack.io/about/"&gt;Matestack&lt;/a&gt;. To Add this is was so very simple, low complexity and it took about 20 minutes.&lt;/p&gt;

&lt;p&gt;In the Matestack view that serves up the map page, I added the menu style controls. This looks deceptively simple; behind the scenes it emits an event carrying map style data when a button is clicked.&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;style_menu_partial&lt;/span&gt;
  &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="s2"&gt;"style-menu"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="ss"&gt;emit: &lt;/span&gt;&lt;span class="s2"&gt;"set_map_style"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="s1"&gt;'mapbox://styles/mapbox/satellite-v9'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;bs_btn&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'btn-sm'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s1"&gt;'Satellite'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="ss"&gt;emit: &lt;/span&gt;&lt;span class="s2"&gt;"set_map_style"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="s1"&gt;'mapbox://styles/mapbox/satellite-streets-v11'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;bs_btn&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'btn-sm'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s1"&gt;'Satellite Streets'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="ss"&gt;emit: &lt;/span&gt;&lt;span class="s2"&gt;"set_map_style"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="s1"&gt;'mapbox://styles/keithrowell/cks2myz68312b17p6133ihn7m'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;bs_btn&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'btn-sm'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s1"&gt;'Regular'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the &lt;code&gt;onLoaded&lt;/code&gt; for the map javascript page, I registered an event to receive info about a map style to change to.&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-javascript"&gt;&lt;span class="nf"&gt;onLoaded&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MatestackUiCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventHub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;set_map_style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setMapStyle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also in the map javascript page, define the function that handles the data sent by the &lt;code&gt;set_map_style&lt;/code&gt; event, setting the map style via the &lt;a href="https://docs.mapbox.com/mapbox-gl-js/api/"&gt;Mapbox GL API&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-javascript"&gt;&lt;span class="nf"&gt;setMapStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here’s what I got.&lt;/p&gt;

&lt;figure&gt;
&lt;img src="/blog/articles/adding_different_map_styles_to_mapbox_map_in_matestack.md.images/map_view.png" alt="Satellite Street View"&gt;
&lt;figcaption&gt;Satellite Street View&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;So elegant and so easy. That’s &lt;a href="https://docs.matestack.io/about/"&gt;Matestack&lt;/a&gt;.&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/27</id>
    <published>2022-01-14T20:45:00+10:00</published>
    <updated>2026-10-04T09:18:13+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/27-ruby-3-1-hash-value-omission"/>
    <title>Ruby 3.1 Hash Value Omission</title>
    <content type="html">&lt;p&gt;Ruby 3.1 introduces a neat feature (&lt;a href="https://bugs.ruby-lang.org/issues/14579"&gt;Feature #14579&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;Values in Hash literals and keyword arguments can be omitted.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{x:, y:}&lt;/code&gt; is syntactic sugar for &lt;code&gt;{x: x, y: y}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;foo(x:, y:)&lt;/code&gt; is syntactic sugar for &lt;code&gt;foo(x: x, y: y)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For a real world example, this code:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="no"&gt;ActionCable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;broadcast&lt;/span&gt; &lt;span class="s1"&gt;'matestack_ui_core'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;event: &lt;/span&gt;&lt;span class="s1"&gt;'route_status_update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;very_late_count: &lt;/span&gt;&lt;span class="n"&gt;very_late_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;late_count: &lt;/span&gt;&lt;span class="n"&gt;late_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;nominal_count: &lt;/span&gt;&lt;span class="n"&gt;nominal_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;early_count: &lt;/span&gt;&lt;span class="n"&gt;early_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;very_early_count: &lt;/span&gt;&lt;span class="n"&gt;very_early_count&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;becomes:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="no"&gt;ActionCable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;broadcast&lt;/span&gt; &lt;span class="s1"&gt;'matestack_ui_core'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;event: &lt;/span&gt;&lt;span class="s1"&gt;'route_status_update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;very_late_count&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt;
  &lt;span class="n"&gt;late_count&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt;
  &lt;span class="n"&gt;nominal_count&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt;
  &lt;span class="n"&gt;early_count&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt;
  &lt;span class="ss"&gt;very_early_count:
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/25</id>
    <published>2022-01-13T18:00:00+10:00</published>
    <updated>2026-10-04T09:18:13+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/25-python-wtf"/>
    <title>Python WTF</title>
    <content type="html">&lt;p&gt;Python is actually a pretty decent language, but from a design perspective, it’s fucked. Ok fucked is a bit strong, but Python could have been much neater and more concise if a little good design had been applied.&lt;/p&gt;

&lt;p&gt;Take a look at this very small, very simple bit of code (a Sublime Text 3 example plugin).&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-python"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sublime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sublime_plugin&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sublime_plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is certainly a trivial example and with so little code, there’s not much scope in which to find design issues.&lt;/p&gt;

&lt;p&gt;Hold my beer.&lt;/p&gt;

&lt;p&gt;Let’s start with the import declaratives. Not identifying the module with text means that it’s difficult to do so dynamically. Maybe Python thought of a way around this and you can actually import modules without knowing their names at the time of writing the code. But if they did, they missed the point. It could have been much simpler, just specify the module name as a string.&lt;/p&gt;

&lt;p&gt;Then the class definition. Looks like the class is defined as a function of f(x), its superclass. Doesn’t seem very OO now does it?&lt;/p&gt;

&lt;p&gt;Then the &lt;code&gt;def run(self, edit):&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Really, do we have to pass in self every fucking time? How about just make it an implicit part of the scope of the function’s code? And the &lt;code&gt;:&lt;/code&gt;, that seems redundant too. What’s the indenting for?&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/17</id>
    <published>2022-01-12T18:00:00+10:00</published>
    <updated>2026-10-03T14:48:19+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/17-formula-1-track-limits"/>
    <title>Formula 1 Track Limits</title>
    <content type="html">&lt;p&gt;Throughout the 2020 and 2021 seasons, every race weekend, track limits was a contentious issue. It&amp;#8217;s always a topic for commentators, and not just that drivers are exceeding track limits, that&amp;#8217;s not the problem, rather that track limit rules are being made up on the go.&lt;/p&gt;

&lt;p&gt;Despite the rules already doing so, race direction defines the limits of the track at each circuit each race weekend. Different corners have different definitions. Sometimes the white line, sometimes the red and white curb, sometimes the green area beyond the curb. Even worse, these definitions change during the course of the weekend. And if it weren&amp;#8217;t true it&amp;#8217;d probably be unbelievable, sometimes definition of the edge of the track changes &lt;em&gt;mid session&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The track limit rules are &lt;em&gt;somewhat&lt;/em&gt; clear in the &lt;a href="https://www.fia.com/regulation/category/110"&gt;Formula 1 Sporting Regulations&lt;/a&gt;. Part of article 27.3:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Drivers must make every reasonable effort to use the track at all times and may not leave the track without a justifiable reason.&lt;/p&gt;

&lt;p&gt;Drivers will be judged to have left the track if no part of the car remains in contact with it and, for the avoidance of doubt, any white lines defining the track edges are considered to be part of the track but the kerbs are not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, that the white line is the edge of the track is not the main point of the only sentence that defines the edge of the track. It could easily be a lot clearer, but the intention that the white line is the edge of the track is definitely there.&lt;/p&gt;

&lt;p&gt;Imagine if during a grand slam tennis match, the umpire says actually from now on where going to the use doubles' line for the edge of the court. Oh and from now on on the line is out. If that happened at the Australian Open it would rain beer cans, or plastic cups or whatever they serve there.&lt;/p&gt;

&lt;p&gt;So what&amp;#8217;s the solution? Change the rules to reflect what happens in the real world so race direction can decide willy nilly what the edge of the track is? Doesn&amp;#8217;t sound very good, but it would actually be an improvement on the current situation, at least race direction would be within the rules.&lt;/p&gt;

&lt;p&gt;The obvious-when-you-see-it solution is to adjust the track before the race. If there&amp;#8217;s a need to have cars running wide at certain corners, decide that &lt;em&gt;before&lt;/em&gt; the race weekend, get the paint can out and paint a new white line. Then stick to the rules.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/article/formula-1-respect"&gt;Respect&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/16</id>
    <published>2022-01-12T03:00:00+10:00</published>
    <updated>2026-10-03T14:48:19+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/16-formula-1-has-a-respect-problem"/>
    <title>Formula 1 has a Respect Problem</title>
    <content type="html">&lt;p&gt;Formula 1 has some problems. Inconsistency in stewarding decisions, Spa non-grand prix no-money-back-for-fans situation, track limits and of course the &lt;a href="blog/article/formula-1-finale-fiasco-2021"&gt;farcical 2021 decider&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think all of these problems stem from a higher level cultural problem of a lack of respect. To me they show a lack of respect for the rules, the drivers, the fans, the sport and even itself.&lt;/p&gt;

&lt;p&gt;How would I come to such a conclusion? Let&amp;#8217;s look at the rules. The track limits situation to me has to come from a disrespect of the rules. Perhaps not a direct and intentional disrespect but an indirect disrespect by thinking that the FIA is bigger and better than the rules and thus can do whatever the fuck it likes.&lt;/p&gt;

&lt;p&gt;The 2021 final race is another extraordinary example of disrespect for the rules. That was a case of either a direct disregarding of the rules or a lack of understanding of the rules. Neither of those should exist if the FIA really had respect for the rules.&lt;/p&gt;

&lt;p&gt;And to have respect for the rules, you probably have to come from a position of respecting fans, teams, etc.&lt;/p&gt;

&lt;p&gt;The Spa non-grand prix was a great example of the FIA&amp;#8217;s disrespect for fans. Loyal and fanatical fans that pay hundreds of Euros per ticket to stand in the rain and not get to see a race. Race Direction&amp;#8217;s decision to run a minimum number of laps under safety car conditions so they could declare a race was run and therefore not refund fans any of their money doesn&amp;#8217;t look good.&lt;/p&gt;

&lt;p&gt;Formula 1 kind of positions itself on a platform of respect with its admirable support for &lt;a href="https://www.formula1.com/en/toolbar/statement-of-commitment-to-respect-for-human-rights.html"&gt;respect of human rights&lt;/a&gt;. So it&amp;#8217;s odd to me that they would have such a broad ranging lack of respect for essentially everything else in the sport.&lt;/p&gt;

&lt;p&gt;The path to solutions for the FIA is to take a big step back, act with humility, acknowledge mistakes, genuinely decide to have a position of real respect for the sport, teams, drivers and fans. To drive everything they do from that position of respect.&lt;/p&gt;

&lt;p&gt;This is just a &lt;em&gt;path&lt;/em&gt; to solutions and doesn&amp;#8217;t itself solve anything directly. But having this culture and mindset of respect would give Formula 1 the framework to allow and guide the many and varied solutions it needs to fix its problems. The individual solutions to each problem must come from this position of respect if they are to have any chance of getting it right.&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/18</id>
    <published>2022-01-11T18:00:00+10:00</published>
    <updated>2026-10-03T14:48:19+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/18-a-formula-for-time-it-takes-a-government-body-in-australia-to-complete-a-task"/>
    <title>A Formula for Time It Takes a Government Body in Australia to Complete a Task</title>
    <content type="html">&lt;p&gt;Governments in Australia tend to be reactionary rather than proactive. We&amp;#8217;ve seen this a lot in the last couple of years where stakes are high and action needs to be taken. The required action usually gets taken as a reaction to the mess the action should would otherwise avoid.&lt;/p&gt;

&lt;p&gt;A formula for when a government in Australia (Federal, State, you name it):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DC = DT + DSF&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DC&lt;/code&gt;: Date Completed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DT&lt;/code&gt;: Duration of Task&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DSF&lt;/code&gt;: Date when Shit hits the Fan&lt;/p&gt;

&lt;p&gt;Usually a critical mass of media criticism or when the otherwise avoidable problem actually becomes a problem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/24</id>
    <published>2022-01-10T01:00:00+10:00</published>
    <updated>2026-10-03T14:48:19+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/24-productivity-on-a-pedestal"/>
    <title>Productivity on a Pedestal</title>
    <content type="html">&lt;p&gt;I was having coffee with a friend the other day and heard a wonderful story.&lt;/p&gt;

&lt;p&gt;We were talking about the changes Covid lockdowns have affected on working lives and in that context came a story of an employee working for a large integrated services corporate. It&amp;#8217;s a company I have worked for in the recent past and I&amp;#8217;m not going to name them but those who know me will know the company I am talking about.&lt;/p&gt;

&lt;p&gt;The large integrated services corporate – which I&amp;#8217;ll call &amp;#8220;the company&amp;#8221; – having been forced to allow employees to work from home (this doesn&amp;#8217;t really fit with the company&amp;#8217;s culture), has deployed software on its employees laptops that measures their &amp;#8220;productivity&amp;#8221;.
We were talking about the changes Covid lockdowns have affected on working lives and in that context came a story of an employee working for a large integrated services corporate.&lt;/p&gt;

&lt;p&gt;The software measures how often the mouse is moved on the employee&amp;#8217;s laptop and figures that if the mouse is moving, at least periodically, the employee is being productive. This actually measures a proxy that doesn&amp;#8217;t really correlate to productivity at all, but that&amp;#8217;s beside the point.
The large integrated services corporate – which I&amp;#8217;ll call &amp;#8220;the company&amp;#8221; – having been forced to allow employees to work from home (the company is against such &amp;#8220;freedoms&amp;#8221;), has deployed software on its employees laptops that measures their &amp;#8220;productivity&amp;#8221;. The company measures how often the mouse is moved on the employee&amp;#8217;s laptop and figures that if the mouse is moving, at least periodically, the employee is working. This actually measures a proxy that doesn&amp;#8217;t really correlate to productivity at all, but that&amp;#8217;s beside the point.&lt;/p&gt;

&lt;p&gt;The clever employee, having completed all his work tasks, now wanted to watch a bit of cricket. But in doing so, lack of mouse movement on his computer would lead the company to believe he wasn&amp;#8217;t being productive. Presumably some middle manager would be looking at compiled reports of employee productivity based on mouse movement.
The clever employee, having completed all his work tasks, now wanted to watch a bit of cricket. But in doing so would lead the company, his employer, to believe he wasn&amp;#8217;t being productive. Presumably some middle manager would be looking at compiled reports of employee productivity based on mouse movement.&lt;/p&gt;

&lt;p&gt;So he connects an external mouse to his laptop, hooks up a tether from the mouse to a pedestal fan which, as it oscillates, causes the mouse to move. Now the pedestal fan is doing his work for him and he is more productive than ever.&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/20</id>
    <published>2022-01-05T01:11:00+10:00</published>
    <updated>2026-10-04T00:34:03+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/20-love-god-and-murder"/>
    <title>Love, God and Murder</title>
    <content type="html">&lt;p&gt;A collection of some of my favourite Nick Cave lyrics.&lt;/p&gt;

&lt;div class="nick-cave lyrics"&gt;

&lt;blockquote&gt;
&lt;p&gt;From the first day I saw her I knew she was the one&lt;br /&gt;
She stared in my eyes and smiled&lt;br /&gt;
For her lips were the colour of the roses&lt;br /&gt;
That grew down the river, all bloody and wild&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Where the Wild Roses Grow&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;What about God and his Armageddon?&lt;br /&gt;
He&amp;#8217;s all blissed out, man, up in heaven&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– There is a Light&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;She saw the barkeep and said oh god he can&amp;#8217;t be dead&lt;br /&gt;
Stag said well just count the holes in the motherfucker&amp;#8217;s head&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Stagger Lee&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;Be mindful of the prayers you send&lt;br /&gt;
Pray hard but pray with care&lt;br /&gt;
For the tears that you are crying now&lt;br /&gt;
Are just your answered prayers&lt;br /&gt;
The ladders of life that we scale merrily&lt;br /&gt;
Move mysteriously around&lt;br /&gt;
So that when you think you&amp;#8217;re climbing up, man&lt;br /&gt;
In fact you&amp;#8217;re climbing down&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Oh my Lord&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;Well they killed a little whiskey&lt;br /&gt;
And poured their pistols dry&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Crow Jane&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;My desire for you is endless&lt;br /&gt;
And I love you most of all&lt;br /&gt;
I just don&amp;#8217;t want you no more&lt;br /&gt;
And that&amp;#8217;s the sweetest embrace of all&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Sweetest Embrace&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;But there was a chord in you that I could not find to strike&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Jesus of the Moon&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;Here she comes blockin' the sun&lt;br /&gt;
Blood runnin' down the inside of her legs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Do you Love Me?&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;A life-sentence sweeping confetti from the floor of a concrete hole&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Let Love In&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;And my piano crouched in the corner of my room&lt;br /&gt;
With all its teeth bared&lt;br /&gt;
All its teeth bared&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Hallelujah&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;I could not wipe the smile from my face&lt;br /&gt;
As I sat sadly by her side&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– As I Sat Sadly by Her Side&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;And she is moving the furniture around&lt;br /&gt;
Moving the furniture around&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Sorrowful Wife&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;I counted up my blessings&lt;br /&gt;
And counted only one&lt;br /&gt;
One tiny little blessing&lt;br /&gt;
And now that blessing&amp;#8217;s gone&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Brother My Cup is Empty&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;So buy me one more drink my brother&lt;br /&gt;
Then I&amp;#8217;ll take it to the road&lt;br /&gt;
Yes I&amp;#8217;ll take it to the rain&lt;br /&gt;
I&amp;#8217;ll take it to the snow&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Brother My Cup is Empty&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;It&amp;#8217;s early in the morning and I don&amp;#8217;t know what to do&lt;br /&gt;
It&amp;#8217;s early in the morning and I can&amp;#8217;t believe it&amp;#8217;s true&lt;br /&gt;
It&amp;#8217;s early in the morning and it&amp;#8217;s happening again&lt;br /&gt;
Well I called you once&lt;br /&gt;
I called you twice&lt;br /&gt;
Ain&amp;#8217;t I your midnight man?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Midnight Man&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;The thunder from my steely fist&lt;br /&gt;
It made all the glasses jangle&lt;br /&gt;
When I shot him I was so handsome&lt;br /&gt;
It was the light&lt;br /&gt;
It was the angle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– O&amp;#8217;Malley&amp;#8217;s Bar&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;What&amp;#8217;s your pleasure? asked the barman&lt;br /&gt;
He had a face like boiled meat&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– The Ballad of Betty Coltrane and Robert Moore&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;She was given to me to put things right&lt;br /&gt;
And I stacked all my accomplishments beside her&lt;br /&gt;
Yet I seemed so obsolete and small&lt;/p&gt;

&lt;p&gt;I found God and all his devils inside her&lt;br /&gt;
In my bed she cast the blizzard out&lt;br /&gt;
Mock sun blazed upon her head&lt;/p&gt;

&lt;p&gt;And so completely filled with light she was&lt;br /&gt;
Her shadow fanged and hairy and mad&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Do you love me?&lt;/p&gt;

&lt;br&gt;

&lt;blockquote&gt;
&lt;p&gt;The tears are welling in my eyes again&lt;br /&gt;
I need twenty big buckets to catch them in&lt;br /&gt;
Twenty pretty girls to carry them down&lt;br /&gt;
Twenty deep holes to burry them in&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Hallelujah&lt;/p&gt;

&lt;/div&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/11</id>
    <published>2022-01-05T01:11:00+10:00</published>
    <updated>2026-10-03T14:48:19+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/11-nick-cave-and-a-train-to-berlin"/>
    <title>Nick Cave and a Train to Berlin</title>
    <content type="html">&lt;div class="nick-cave"&gt;

&lt;p&gt;On a train trip across Germany a few years ago, I had an idea. I would listen to all of my favourite Nick Cave songs and jot down the lyrics that move me. Over a six hour train ride to Berlin&lt;a href="#fn:1" id="fnref:1" title="see footnote" class="footnote"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, that&amp;#8217;s what I did.&lt;/p&gt;

&lt;p&gt;6 hours of Nick Cave is a wild ride, make no mistake. It&amp;#8217;s a dark and turbulent world. In his own words&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is an absurd, crazy, violent world where people rage away and God actually exists.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This piece by Nick Groom, &lt;a href="http://www.thelineofbestfit.com/features/listomania/the-ten-best-nick-cave-lyrics-137079"&gt;The Ten Best Nick Cave Lyrics&lt;/a&gt;, describes Cave&amp;#8217;s writing particularly well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nick Cave’s writing is utterly singular: a bilious mix of the sacred and the profane fuels his lyrics. Biblical prophecy is mashed up with voodoo, parable and fable clash with lullabies and proverbs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Utterly singular. Yes. One of the best song writers of our time, I say.&lt;/p&gt;

&lt;p&gt;So here it is, a collection of some of my favourite Nick Cave lyrics: &lt;a href="love-god-and-murder"&gt;Love, God and Murder&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;

&lt;li id="fn:1"&gt;
&lt;p&gt;Berlin was a fitting destination as Cave lived and wrote some of his work in Berlin. &lt;a href="#fnref:1" title="return to body" class="reversefootnote"&gt;&amp;#160;&amp;#8617;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/4</id>
    <published>2022-01-01T19:00:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/4-a-year-with-a-camera-2021"/>
    <title>A Year With a Camera 2021</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2021 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2021.md.images/2021_a_year_with_a_camera.mp4" title="A Year With a Camera 2021"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2021.md.images/a_year_with_a_camera_2021.png" alt="A Year With a Camera 2021" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/26</id>
    <published>2021-01-05T19:00:00+10:00</published>
    <updated>2026-10-04T09:18:13+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/26-rails-7-transforms-a-ruby-hash-into-html-attributes-for-erb-interpolation"/>
    <title>Rails 7 Transforms a Ruby Hash into HTML attributes for ERB Interpolation</title>
    <content type="html">&lt;p&gt;Before Rails 7, we did stuff like this:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-html"&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= pet[:image_url] %&amp;gt;"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= pet[:name] %&amp;gt;"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data-breed=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= pet[:breed] %&amp;gt;"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data-color=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= pet[:color] %&amp;gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which gives:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-html"&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"http://bit.ly/lily-the-cat"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Lilyhammer"&lt;/span&gt; &lt;span class="na"&gt;data-breed=&lt;/span&gt;&lt;span class="s"&gt;"Ragdoll"&lt;/span&gt; &lt;span class="na"&gt;data-color=&lt;/span&gt;&lt;span class="s"&gt;"white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;HTML with interpolated ruby courtesy of ERB.&lt;/p&gt;

&lt;p&gt;With Rails 7 you can do this:&lt;/p&gt;

&lt;p&gt;Using tag helper&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-erb"&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;img&lt;/span&gt; &lt;span class="ss"&gt;src: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:image_url&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;alt: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;breed: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:breed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using content_tag&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-erb"&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;content_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;src: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:image_url&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;alt: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;breed: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:breed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Is that better? Maybe better in that you don’t have to so much of the ERB interpolation syntax of opening and closing &lt;code&gt;&amp;lt;%= %&amp;gt;&lt;/code&gt;. But we’re now abstracted from the intention of the code, which is to produce an image tag.&lt;/p&gt;

&lt;p&gt;Now, the fact that we want an image tag is a dereferencing of the image tag &lt;code&gt;img&lt;/code&gt; with &lt;code&gt;tag.img&lt;/code&gt; then all that detail. But still all inside &lt;code&gt;&amp;lt;%= %&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Even worse, with the second example using the &lt;code&gt;content_tag&lt;/code&gt; helper, the information that we have an image tag is now a symbol &lt;code&gt;:img&lt;/code&gt;, a piece of data for the &lt;code&gt;content_tag&lt;/code&gt;. The important fact of what tag we’re using is put on the same conceptual plane as all the other guff the image tag needs. The image tag is lost in the weeds of its own detail.&lt;/p&gt;

&lt;p&gt;When reading this code, assume it would be among lots of other similar code, we need to be able to scan though and understand the structure. Image, inside a span, inside a div, etc. Now, with that detail hidden in the weeds, it’s no longer in plain sight.&lt;/p&gt;

&lt;p&gt;I think a whole page of HTML rendered this was would be much harder to read than ERB HTML.&lt;/p&gt;

&lt;p&gt;Is there a better way? There’s a clue above. It’s implied that one &lt;code&gt;&amp;lt;%= %&amp;gt;&lt;/code&gt; is better than many. From there I will infer that zero &lt;code&gt;&amp;lt;%= %&amp;gt;&lt;/code&gt; are better than many or even any.&lt;/p&gt;

&lt;p&gt;What if we could write this?:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ss"&gt;src: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:image_url&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;alt: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s1"&gt;'data-breed'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:breed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s1"&gt;'data-color'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Less punctuation, no more ERB interpolation and the image tag is back as a first class concept rather than piece of data! The intention is very clear.&lt;/p&gt;

&lt;p&gt;Well… it &lt;em&gt;can&lt;/em&gt; be written just like that. With &lt;a href="https://www.matestack.io"&gt;Matestack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We could even model the structure of the &lt;code&gt;data&lt;/code&gt; parts more closely resembling their semantics:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ss"&gt;src: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:image_url&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;alt: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;breed: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:breed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:color&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here’s a real code snippet using &lt;a href="https://www.matestack.io"&gt;Matestack&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'card shadow-sm border-0 bg-light'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'w-100'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
  &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'card-body'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;h5&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
    &lt;span class="n"&gt;paragraph&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'card-text'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Look at how nice that is to read. And it can be packaged up as a component for later use like:&lt;/p&gt;

&lt;pre class="highlight"&gt;&lt;code class="language-ruby"&gt;&lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'some-section'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;card&lt;/span&gt; &lt;span class="ss"&gt;image: &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body: &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/3</id>
    <published>2021-01-01T19:00:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/3-a-year-with-a-camera-2020"/>
    <title>A Year With a Camera 2020</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2020 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2020.md.images/2020_a_year_with_a_camera.mp4" title="A Year With a Camera 2020"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2020.md.images/a_year_with_a_camera_2020.png" alt="A Year With a Camera 2020" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/2</id>
    <published>2020-01-01T19:30:00+10:00</published>
    <updated>2026-10-04T08:39:25+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/2-a-year-with-a-camera-2019"/>
    <title>A Year With a Camera 2019</title>
    <content type="html">&lt;p&gt;A video montage of how I saw 2019 through the lens of a camera. Click the image to start the video.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/a_year_with_a_camera_2019.md.images/2019_a_year_with_a_camera.mp4" title="A Year With a Camera 2019"&gt;&lt;img src="/blog/articles/a_year_with_a_camera_2019.md.images/a_year_with_a_camera_2019.png" alt="A Year With a Camera 2019" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
  <entry>
    <id>tag:blog.keithrowell.com,2005:Article/9</id>
    <published>2017-01-08T08:11:00+10:00</published>
    <updated>2026-10-03T14:48:19+10:00</updated>
    <link rel="alternate" type="text/html" href="https://blog.keithrowell.com/article/9-charlotte-s-first-song-on-a-piano"/>
    <title>Charlotte's First Song on a Piano</title>
    <content type="html">&lt;p&gt;I was lucky to anticipate that Charlotte was about to sit at the piano and do something and have the video rolling.&lt;/p&gt;

&lt;p&gt;I just love the free expression and that there are a couple of separate and distinct passages in the &amp;#8220;piece&amp;#8221;. It has a kind of melody to it, varying shades of light and dark, some nice pauses. If I listen to it without looking and trying to forget that it&amp;#8217;s a 4 year old, it almost sounds like a nice bit of obscure jazz.&lt;/p&gt;

&lt;p&gt;&lt;a href="/blog/articles/charlottes_first_song_on_a_piano.md.images/charlottes_first_song_on_a_piano.mp4" title="Charlotte's First Song on a Piano"&gt;&lt;img src="/blog/articles/charlottes_first_song_on_a_piano.md.images/charlottes_first_song_on_a_piano.png" alt="Charlotte's First Song on a Piano" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    <author>
      <name>Keith Rowell</name>
    </author>
  </entry>
</feed>
