<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Dom Christie</title><description>UK-based design engineer specialising in Ruby on Rails, JavaScript, and Web Audio.</description><link>https://domchristie.co.uk/</link><item><title>Custom Path Configuration Properties in Hotwire Native iOS</title><link>https://domchristie.co.uk/posts/custom-path-configuration-properties-hotwire-native-ios/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/custom-path-configuration-properties-hotwire-native-ios/</guid><description>&lt;p&gt;Path Configuration rules in Hotwire Native provides a way for customising how a view is displayed for a particular URL pattern. Out-the-box it supports customising:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the view’s &lt;code&gt;context&lt;/code&gt; (e.g. modal screen)&lt;/li&gt;
&lt;li&gt;the view’s &lt;code&gt;presentation&lt;/code&gt; i.e. how it impacts the navigation stack&lt;/li&gt;
&lt;li&gt;functional tweaks, such as “Done” and “Back” button display&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The documentation also states: &lt;q&gt;You are free to add more [rule] properties as your app needs&lt;/q&gt;, yet it doesn’t mention how you can access them, or how you might use them. So after a bit of digging, and some pointers from Joe Masilotti, here’s what I’ve discovered…&lt;/p&gt;
&lt;p&gt;You can access the properties that match a given URL with the following:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Hotwire.config.pathConfiguration.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: url)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then to use this to customise a web view, subclass &lt;code&gt;HotwireWebViewController&lt;/code&gt;. For example, to hide the navigation bar on a &lt;code&gt;/login&lt;/code&gt; page, your path configuration might look like this:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;&quot;patterns&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/login&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;&quot;navigation_bar_hidden&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With your custom view:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;HotwireNative&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;AppWebViewController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: HotwireWebViewController {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;viewWillAppear&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; animated: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;viewWillAppear&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(animated)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; properties &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Hotwire.config.pathConfiguration.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: currentVisitableURL)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; navHidden &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; properties[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;navigation_bar_hidden&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;as?&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        navigationController&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;setNavigationBarHidden&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(navHidden, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;animated&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then configure Hotwire to use this view by default, e.g. in &lt;code&gt;AppDelegate&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Hotwire.config.defaultViewController &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { url &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;AppWebViewController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Mon, 02 Jun 2025 13:39:24 GMT</pubDate></item><item><title>Component Partials in Rails</title><link>https://domchristie.co.uk/posts/component-partials/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/component-partials/</guid><description>&lt;p&gt;I presented some thoughts about Rails partials at April’s &lt;a href=&quot;https://www.meetup.com/brighton-ruby-group/&quot;&gt;Brighton Ruby meetup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first half discussed various ways to render partials and collections of objects, including using &lt;code&gt;to_partial_path&lt;/code&gt;. An example might be rendering a dynamic navigation bar where the navigation items differ depending on the user’s role, e.g. if they’re logged in, or paid, etc. We can create a plain old Ruby object with a &lt;code&gt;to_partial_path&lt;/code&gt; method that returns the path of the partial to render. That class can include all the necessary logic, keeping the partial relatively clean:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# app/helpers/navigations_helper.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;NavigationsHelper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;navigation&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(user)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Navigation&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(user)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Navigation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(user)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      @user &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;to_partial_path&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;navigations/navigation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# decides which items to show based on user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;items&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, root_path), …]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Item&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;#…&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;to_partial_path&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;navigations/item&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/navigations/_navigation.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= render navigation.items %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our call to render the navigation is also tidy:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/layouts/application.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= render navigation(current_user) %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;The second half of the talk demonstrated a derivation of a slotted partial system in around 20 lines-of-code:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;PartialsHelper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;component_partial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Partial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(view_context)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      @view_context &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; view_context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      @contents &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Hash&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { |h, k| h[k] &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;SafeBuffer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;content_for&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(name, content &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; content &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        content &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; @view_context.capture(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;block) &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        @contents[name] &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; content.to_s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        @contents[name].presence&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With usage as follows:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/components/_card.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; partial &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; component_partial %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;…&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= partial.content_for(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:image&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&amp;#x3C;%= partial.content_for(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:heading&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;…&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= partial.content_for(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:description&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/products/_product.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= render &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |partial| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;% partial.content_for &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:image&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= image_tag product.image %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;% partial.content_for &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:heading&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, product.name %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;% partial.content_for &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:description&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= simple_format product.description %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pattern forms the basis of the &lt;a href=&quot;https://github.com/bullet-train-co/nice_partials&quot;&gt;nice_partials gem&lt;/a&gt;, which includes a ton of extra niceties.&lt;/p&gt;</description><pubDate>Thu, 03 Apr 2025 14:40:39 GMT</pubDate></item><item><title>Turbo Native without Turbo?</title><link>https://domchristie.co.uk/posts/turbo-native-without-turbo/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/turbo-native-without-turbo/</guid><description>&lt;p&gt;&lt;a href=&quot;https://signalvnoise.com/posts/3743-hybrid-sweet-spot-native-navigation-web-content&quot;&gt;Native navigation with web content&lt;/a&gt; is a popular approach to building mobile apps. It’s used by some of the biggest companies in the world, including BBC and Amazon.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://37signals.com&quot;&gt;37signals&lt;/a&gt; have open-source adapters using this idea, enabling web apps that use &lt;a href=&quot;https://github.com/hotwired/turbo&quot;&gt;Turbo&lt;/a&gt; on the front-end to create native navigation experiences on &lt;a href=&quot;https://github.com/hotwired/turbo-ios&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://github.com/hotwired/turbo-android&quot;&gt;Android&lt;/a&gt;. These depend on Turbo, but what if you prefer another client-side library, such as &lt;a href=&quot;http://htmx.org/&quot;&gt;htmx&lt;/a&gt;, or &lt;a href=&quot;https://inertiajs.com&quot;&gt;Inertia.js&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Turbo’s process is quite straightforward: intercept link clicks, fetch the content, and render the new content. This forms the concept of a Turbo &lt;code&gt;Visit&lt;/code&gt;. Turbo triggers &lt;code&gt;Visit&lt;/code&gt; lifecycle events that are sent to the native adapter, which then can update the navigation stack. Libraries such as htmx and Inertia.js  follow similar approach, so as long as these libraries offer a comprehensive event system, is should be possible to create a translation layer.&lt;/p&gt;
&lt;p&gt;I have been experimenting with creating a translation layer for htmx, and it looks like it’s possible. It consists of two parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/domchristie/turbo-native-htmx-driver&quot;&gt;turbo-native-htmx-driver&lt;/a&gt;: translates htmx events into Turbo Native adapter method calls.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/domchristie/turbo-shim&quot;&gt;turbo-shim&lt;/a&gt;: a universal shim that implements the basic methods required for the Turbo Native adapters. It provides the way to register drivers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ve targeted iOS for now, and here it is working with the Turbo Native demo:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/turbo-htmx.gif&quot; alt=&quot;A screen capture of an iOS navigation stack&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you’re interested in this idea, please get in touch.&lt;/p&gt;</description><pubDate>Fri, 19 Jul 2024 09:27:51 GMT</pubDate></item><item><title>Optimistic UI with Ruby on Rails &amp; Hotwire</title><link>https://domchristie.co.uk/posts/optimistic-ui-hotwire-rails/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/optimistic-ui-hotwire-rails/</guid><description>&lt;p&gt;&lt;em&gt;This post details a proof-of-concept for optimistic UI. If you want to just browse the source, check out the &lt;a href=&quot;https://github.com/domchristie/optimistic-ui-hotwire-rails&quot;&gt;optimistic-ui-hotwire-rails GitHub repository&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Optimistic UI enhances perceived speed and responsiveness by immediately updating the UI with an expected state before the server&apos;s response is received. This approach is used when the application can predict the outcome of an action based on context and user input, allowing for an immediate response to actions.&lt;/p&gt;
&lt;cite&gt;&lt;a href=&quot;https://remix.run/docs/en/main/discussion/pending-ui&quot;&gt;Pending and Optimistic UI&lt;/a&gt; on the Remix Docs&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Optimistic UI is tricky for apps that predominantly render their HTML on the server. However, in simple cases where we can reasonably predict the outcome of a user action, we can achieve a &lt;a href=&quot;https://www.youtube.com/watch?t=701&amp;#x26;v=SWEts0rlezA&quot;&gt;Good Enough&lt;/a&gt;™️ experience.&lt;/p&gt;
&lt;p&gt;The Hotwire example below takes the follow approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pre-render the HTML with placeholders for content&lt;/li&gt;
&lt;li&gt;When a form is submitted, replace the placeholders with real content&lt;/li&gt;
&lt;li&gt;Use Turbo Stream Actions to insert the new HTML&lt;/li&gt;
&lt;li&gt;The server re-renders the page, displaying the persisted comment&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;optimistic-comments&quot;&gt;Optimistic Comments&lt;/h2&gt;
&lt;p&gt;Let’s create a basic form that lets users submit a comment. Our &lt;code&gt;comments/index.html.erb&lt;/code&gt; template might look like:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= turbo_refreshes_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;scroll:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:preserve&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= form_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; @comment &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |form| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= form.text_field &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:body&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;autofocus:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= form.submit &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Send&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comments&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= render @comments %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;… backed by a controller:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;CommentsController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @comment &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Comment&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @comments &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Comment&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.all.order(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;created_at:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:desc&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @comment &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Comment&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(comment_params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @comment.save&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    redirect_back_or_to comments_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;private&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;comment_params&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    params.require(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:comment&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;).permit(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:body&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally our &lt;code&gt;comments/_comment.html.erb&lt;/code&gt; partial:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comment-body&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;bubble&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &amp;#x3C;%= simple_format comment.body %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= comment.created_at.to_fs(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:short&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re now ready to get optimistic. Our optimistic UI will prepend a new comment immediately, before the server responds and updates the page. But first, we need to refactor &lt;code&gt;comments/_comment.html.erb&lt;/code&gt; so that it can be pre-rendered with placeholders.&lt;/p&gt;
&lt;h2 id=&quot;a-reusable-comment-partial&quot;&gt;A Reusable Comment Partial&lt;/h2&gt;
&lt;p&gt;Our current &lt;code&gt;_comment.html.erb&lt;/code&gt; partial depends on a &lt;code&gt;Comment&lt;/code&gt; instance, but for the pre-rendering stage, we don’t have one. We could create a dummy &lt;code&gt;Comment&lt;/code&gt; object that contains placeholders for the body and footer, but I’ve found it useful to layer up partials like so:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/application/_comment.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comment-body&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;bubble&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &amp;#x3C;%= body %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= footer %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/comments/_comment.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= render &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;application/comment&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;body:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; simple_format(comment.body),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;footer:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; comment.created_at.to_fs(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:short&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, you have a reusable &lt;code&gt;application/_comment.html.erb&lt;/code&gt; partial that can be used in any context—whether it’s rendered with a &lt;code&gt;Comment&lt;/code&gt; or not.
&lt;em&gt;Note: I’ve used local variables here, but you may wish to use a library that supports slots, like &lt;a href=&quot;https://github.com/bullet-train-co/nice_partials&quot;&gt;nice_partials&lt;/a&gt; or &lt;a href=&quot;https://viewcomponent.org/&quot;&gt;ViewComponent&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;pre-rendering-with-placeholders&quot;&gt;Pre-rendering with Placeholders&lt;/h2&gt;
&lt;p&gt;Returning to our comment form, we can now pre-render a comment and set out how it will be inserted with a Turbo Stream Action.&lt;/p&gt;
&lt;p&gt;Our optimistic comment will simply display “Sending…” in the footer. The body will be dynamic, populated with the value of the form’s &lt;code&gt;comment[body]&lt;/code&gt; input. We’ll hook this up later in our Stimulus controller.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# `app/views/comments/index.html.erb` %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# … %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= form_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; @comment, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;controller:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;optimistic-form&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;action:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;optimistic-form#performActions&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |form| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= form.text_field &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:body&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;autofocus:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= form.submit &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Send&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-optimistic-form-target&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= turbo_stream.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;prepend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comments&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;partial:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;application/comment&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;locals:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;body:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;${params[&apos;comment[body]&apos;]}&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;footer:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Sending…&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    } %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We render a Turbo Stream Action that prepends the pre-rendered comment. It’s wrapped in a &lt;code&gt;&amp;#x3C;template&gt;&lt;/code&gt; element so it isn’t executed immediately. In this case, we’re only performing a single action, but this template can contain multiple Turbo Stream Actions if needed.&lt;/p&gt;
&lt;p&gt;Our form is controlled by an &lt;code&gt;optimistic-form&lt;/code&gt; Stimulus controller, which we’ll set up next. On submit, we call &lt;code&gt;optimistic-form#performActions&lt;/code&gt; which activates the actions in the template.&lt;/p&gt;
&lt;p&gt;Finally, we set the &lt;code&gt;body&lt;/code&gt; and &lt;code&gt;footer&lt;/code&gt; locals. The &lt;code&gt;body&lt;/code&gt; uses JavaScript template literal placeholder syntax (&lt;code&gt;${}&lt;/code&gt;). This is important as it will allow us to dynamically insert the form’s &lt;code&gt;comment[body]&lt;/code&gt; value.&lt;/p&gt;
&lt;h2 id=&quot;stimulus-controller&quot;&gt;Stimulus Controller&lt;/h2&gt;
&lt;p&gt;With all this in place, our Stimulus controller just needs to fill the pre-rendered comment with the form’s content, then activate the Turbo Stream Action.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// app/javascript/controllers/optimistic_form_controller.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { Controller } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@hotwired/stimulus&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { fill, escape, raw } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@domchristie/composite&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;OptimisticFormController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Controller&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;targets&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;actions&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;performActions&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.element.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;insertAdjacentHTML&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;beforeend&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.actionsTarget, { params: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.params })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Object.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fromEntries&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;FormData&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.element))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/domchristie/composite&quot;&gt;@domchristie/composite&lt;/a&gt; is a tiny library that takes a &lt;code&gt;&amp;#x3C;template&gt;&lt;/code&gt;, converts its content to a template literal, and fills the placeholders with the given data. Here, we create the data from the form’s &lt;code&gt;FormData&lt;/code&gt;, and pass it to Composite’s &lt;code&gt;fill&lt;/code&gt; function as &lt;code&gt;params&lt;/code&gt;. The comment body is contained in a field named &lt;code&gt;comment[body]&lt;/code&gt;, so we can reference it as &lt;code&gt;params[&apos;comment[body]&apos;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we can activate the Turbo Stream Actions by appending them to the form using &lt;code&gt;insertAdjacentHTML&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;comment-formatting&quot;&gt;Comment Formatting&lt;/h2&gt;
&lt;p&gt;This works, but the comment body is not formatted like that in &lt;code&gt;comments/_comment.html.erb&lt;/code&gt; which uses Rails’ &lt;code&gt;simple_format&lt;/code&gt;. So when the page is replaced with the server-rendered version, the change might be jarring.&lt;/p&gt;
&lt;p&gt;We can fix this by &lt;a href=&quot;https://gist.github.com/kares/740162&quot;&gt;porting Rails’ &lt;code&gt;simple_format&lt;/code&gt; helper to JavaScript&lt;/a&gt;. (Thanks &lt;a href=&quot;https://github.com/kares&quot;&gt;Karol Bucek&lt;/a&gt;!), and providing access to it in the pre-rendered template, via the controller. Note that we’re passing in the controller (&lt;code&gt;this&lt;/code&gt;) into the &lt;code&gt;fill&lt;/code&gt; function to make it available. We’ll use Composite’s &lt;code&gt;escape&lt;/code&gt; and &lt;code&gt;raw&lt;/code&gt; functions to help with this.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// app/javascript/controllers/optimistic_form_controller.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { Controller } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@hotwired/stimulus&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { fill, escape, raw } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@domchristie/composite&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;OptimisticFormController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Controller&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;targets&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;actions&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;performActions&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.element.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;insertAdjacentHTML&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;beforeend&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.actionsTarget, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        params: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.params,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        controller: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Object.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fromEntries&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;FormData&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.element))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;simpleFormat&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;\r\n&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;\n\n&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;&amp;#x3C;/p&gt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;\n\n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&amp;#x3C;p&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;\n]\n&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;)(?=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;\n]&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;$1&amp;#x3C;br/&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;`&amp;#x3C;p&gt;${&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;}&amp;#x3C;/p&gt;`&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can access the &lt;code&gt;controller&lt;/code&gt; in our template, and call &lt;code&gt;controller.simpleFormat&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# `app/views/comments/index.html.erb` %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# … %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= form_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; @comment, … &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |form| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# … %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-optimistic-form-target&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= turbo_stream.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;prepend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comments&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;partial:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;application/comment&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;locals:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;body:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;${controller.simpleFormat(params[&apos;comment[body]&apos;])}&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;footer:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Sending…&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    } %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;styling-optimistic-comments&quot;&gt;Styling Optimistic Comments&lt;/h2&gt;
&lt;p&gt;To communicate whether a comment is optimistic or persisted, we can add a &lt;code&gt;data-optimistic&lt;/code&gt; attribute to the comment, allowing us to style it accordingly.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# `app/views/application/_comment.html.erb` %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7; font-style: italic&quot;&gt;&amp;#x3C;%=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7; font-style: italic&quot;&gt;&quot;data-optimistic&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;local_assigns[:optimistic]&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comment-body&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;bubble&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &amp;#x3C;%= body %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= footer %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# `app/views/comments/index.html.erb` %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# … %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= form_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; @comment, … &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |form| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# … %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-optimistic-form-target&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &amp;#x3C;%= turbo_stream.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;prepend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;comments&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;partial:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;application/comment&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;locals:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;body:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;${controller.simpleFormat(params[&apos;comment[body]&apos;])}&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;footer:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Sending…&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;optimistic:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    } %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* app/assets/stylesheets/application.css */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-optimistic&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;.bubble&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;#666&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;border-color&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;#e6e6e6&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;background-color&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;#f9f9f9&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-final-result&quot;&gt;The Final Result&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls src=&quot;/optimistic-ui.mov&quot;&gt;&lt;/video&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;downsides&quot;&gt;Downsides&lt;/h2&gt;
&lt;p&gt;This approach works best with simple updates: simple components with straightforward markup, and minimal DOM operations—like adding a single comment. Rendering complex elements with dynamic content might be tricky.&lt;/p&gt;
&lt;p&gt;If your optimistic component includes lots of logic, it probably won’t work so well. If your update includes lots of DOM updates, it’ll be hard to keep it in-sync with the server-rendered version. If your template uses lots of helpers (like &lt;code&gt;simple_format&lt;/code&gt;), you may find yourself reimplementing each one in JavaScript. And finally, this currently relies on server-rendered error pages if things go wrong; probably fine if the device is online, but not great otherwise.&lt;/p&gt;
&lt;p&gt;If optimistic UI is a crucial part of your experience and you begin to feel the issues above, then it might be worth exploring alternatives. &lt;a href=&quot;http://mustache.github.io&quot;&gt;Mustache&lt;/a&gt; offers a shared templating system, allowing you to render the same template in different languages. Alternatively you could implement your feature with a client-side framework.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Optimistic UI can be achieved in server-rendered apps with Hotwire. By pre-rendering the UI on the client, filling its content with dynamic (form) data, and activating Turbo Stream Actions, we can get a &lt;em&gt;good enough&lt;/em&gt; experience without the complexity of a client-side framework.&lt;/p&gt;
&lt;p&gt;However, this approach has its limitations. It works best for simple updates, and can be tricky to extend to more complex components. If you find yourself reimplementing lots of Rails helpers in JavaScript, or struggling to keep the client updates and server-rendered version in sync, it might be worth considering a different approach.&lt;/p&gt;</description><pubDate>Sun, 07 Jul 2024 14:53:50 GMT</pubDate></item><item><title>Tailwind Repetition</title><link>https://domchristie.co.uk/posts/tailwind-repetition/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tailwind-repetition/</guid><description>&lt;p&gt;The biggest complaint about Tailwind CSS is that it results in long, ugly lists of class names that are difficult to maintain, particularly if they’re repeated.&lt;/p&gt;
&lt;p&gt;This popped up again the other day, with the following example…
&lt;em&gt;&lt;a href=&quot;https://x.com/coorasse/status/1802628126742086010&quot;&gt;How do you usually avoid this in #tailwind? #rubyonrails&lt;/a&gt;:&lt;/em&gt;&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a traditional CSS approach, it’d be common to create a &lt;code&gt;.nav-link&lt;/code&gt; class, and set the styles in a separate stylesheet. With Tailwind, this approach can be achieved with &lt;code&gt;@apply&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;nav-link&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;nav-link&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;nav-link&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;nav-link&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* application.css */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; components {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;.nav-link&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;text-white&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;px-&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;3 &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;py-&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;2 &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;rounded-md&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;text-sm&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;font-medium&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;:bg-gray-700 data-[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=true]:bg-gray-500;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, one of the key benefits of just using Tailwind’s classes is you don’t have to worry about naming things, or architecting and maintaining your own CSS files. With &lt;code&gt;@apply&lt;/code&gt;, you end up dealing with those considerations.&lt;/p&gt;
&lt;p&gt;So, if &lt;code&gt;@apply&lt;/code&gt; isn’t recommended, what are the other options?&lt;/p&gt;
&lt;p&gt;One of my favourite hidden features of Tailwind is that the ugliness of the class names encourages you to think about how to improve the structure of view code. Here’s an analysis of some of the options mentioned in that thread.&lt;/p&gt;
&lt;h2 id=&quot;alternative-approaches&quot;&gt;Alternative Approaches&lt;/h2&gt;
&lt;h3 id=&quot;1-do-nothing&quot;&gt;1. Do Nothing&lt;/h3&gt;
&lt;p&gt;If this is the only place these classes used, it might be preferable to leave it as-is. The styles may only change very rarely (or not at all), and so updating the list of classes isn’t a maintenance burden. Most editors support multi-cursor editing to help with this.&lt;/p&gt;
&lt;p&gt;If the styles do change frequently, and updates are beginning to hurt, then consider another approach, but just because it’s repetitive and ugly, it doesn’t necessarily mean it’s hard to maintain. While it might seem unsightly, there’s value in patiently waiting for a good abstraction to present itself; &lt;em&gt;now&lt;/em&gt; might not be the right time to shift things around. I’d rather deal with long lists of classes over untangling specificity issues in arbitrarily organised CSS files.&lt;/p&gt;
&lt;p&gt;The benefit here is that there’s no misdirection and no naming decisions. All the styles are there to be seen and updated. What’s more, if one of the links requires custom styles, it’s easy to break out of the standard styles for that exception.&lt;/p&gt;
&lt;h3 id=&quot;2-local-variable&quot;&gt;2. Local Variable&lt;/h3&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% classes &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a good first step to avoiding the repetition. It’s clear, and breaking out of the standard styles would be easy. However, there’s still a fair bit of repetition outside of the class names: &lt;code&gt;&amp;#x3C;%= link_to &quot;…, &quot;…&quot;, class: classes %&gt;&lt;/code&gt;. If we really felt the need to &lt;abbr title=&quot;Don&amp;#x27;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt; it up, we could do better.&lt;/p&gt;
&lt;p&gt;In fact, it looks like the original example failed to include the &lt;code&gt;data-active&lt;/code&gt; attribute, so in reality, an updated version might be:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% classes &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)} %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)} %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)} %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)} %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks similar to the &lt;code&gt;@apply&lt;/code&gt; approach, but it keeps the classes in the same file as the markup. However, we’ve only reduced the repetition of the CSS classes. The &lt;code&gt;current_page?&lt;/code&gt; check is still repetitive. Adding another link would require adding link text, a path, and ensuring the &lt;code&gt;active&lt;/code&gt; logic is correct.&lt;/p&gt;
&lt;h2 id=&quot;3-loop&quot;&gt;3. Loop&lt;/h2&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;].each &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |text, path| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= link_to text, path, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(path)} %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This really cleans up the repetition. The classes and active attributes are only stated once. Adding links is just a case of modifying the array. Breaking out of the styles could be achieved with another option, e.g.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-black text-bold …&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;].each &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |text, path, classes| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= link_to text, path, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; classes &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the deeper benefit is that the code is beginning to reveal potential improvements for how to model the UI. The collection of values suggests the presence of an underlying object.&lt;/p&gt;
&lt;p&gt;If the navigation requirements were to become more complex, you might consider encapsulating these values in a class and rendering them as follows:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# app/models/navigation_item.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;NavigationItem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;attr_reader&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:path&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(path, text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @path &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @text &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;self.all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    ].map {|text, path| &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(path, text) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;NavigationItem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.all.each &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |item| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= link_to item.text, item.path, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then if the markup becomes complex, move it to a partial. By setting &lt;a href=&quot;https://api.rubyonrails.org/classes/ActiveModel/Conversion.html#method-i-to_partial_path&quot;&gt;&lt;code&gt;to_partial_path&lt;/code&gt;&lt;/a&gt; in the class, Rails can automatically lookup and render the partials:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;NavigationItem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;to_partial_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;navigations/item&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/navigations/_item.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to item.path, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# … %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= item.text %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= render &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;NavigationItem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.all %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The downside is that you’ve had to name the concept. However, by this stage, the UI concept is concrete and the naming decision is clear. The HTML can still be written in &lt;code&gt;html+erb&lt;/code&gt; files, and hopefully the styles are established enough to not need frequent updating.&lt;/p&gt;
&lt;p&gt;The best feature of this approach, is that there are clear options as the code grows and becomes more complex. We’ve gone from looping over a bit of data, to looping over objects that represent the data, to partials that are automatically rendered.&lt;/p&gt;
&lt;h2 id=&quot;4-custom-link_to&quot;&gt;4. Custom &lt;code&gt;link_to&lt;/code&gt;&lt;/h2&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= nav_link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= nav_link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= nav_link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= nav_link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;UiHelper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;nav_link_to&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(text, path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    link_to text, path, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(path)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a straightforward approach that encapsulates the markup with the variables passed in. It looks tidy, but I’ve found it can be problematic.&lt;/p&gt;
&lt;p&gt;First, it looks like Rails’ own &lt;code&gt;link_to&lt;/code&gt;, so there might be an expectation that it mirrors that API, but it doesn’t. Of course we could create an identical API that wraps &lt;code&gt;link_to&lt;/code&gt; and adds the classes, but that adds complexity. If Rails extends its &lt;code&gt;link_to&lt;/code&gt; API, our code should follow suit to avoid confusion.&lt;/p&gt;
&lt;p&gt;Second, writing markup in helpers is awkward. Fine for a single element, but too many more and you end up &lt;code&gt;concat&lt;/code&gt;ing strings, or calling &lt;code&gt;html_safe&lt;/code&gt;. As such, this approach isn’t really open to extension.&lt;/p&gt;
&lt;p&gt;Finally, you have to choose how you organise your helpers. Should this live in &lt;code&gt;ApplicationHelper&lt;/code&gt;? Should I create a new helper? &lt;code&gt;UiHelper&lt;/code&gt;? &lt;code&gt;NavigationsHelper&lt;/code&gt;? You immediately end up with the same naming and architecture problems that Tailwind aims to solve.&lt;/p&gt;
&lt;h2 id=&quot;5-actionviewattributes&quot;&gt;5. ActionView::Attributes&lt;/h2&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Home&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, ui.nav_link(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, ui.nav_link(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/projects&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, ui.nav_link(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/monitor&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, ui.nav_link(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;UiHelper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @ui &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Ui&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    delegate_missing_to &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:@view_context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(view_context)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      @view_context &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; view_context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;nav_link&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      tag.attributes &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-white px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700 data-[active=true]:bg-gray-500&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;data:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;active:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; current_page?(path)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/seanpdoyle/action_view-attributes&quot;&gt;ActionView::Attributes gem&lt;/a&gt; enhances Rails’ &lt;code&gt;tag.attributes&lt;/code&gt; helper. It makes it easy to build collections of HTML attributes for sharing in various contexts and elements. It’s really smart about how attributes are merged. For example:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;tag.attributes(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-bold&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;).merge(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;class:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;text-blue-700&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# outputs: &quot;class=&apos;text-bold text-blue-700&apos;&quot;, no clobbering!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can think of this as &lt;em&gt;composition&lt;/em&gt;. For example, we can apply a set of button attributes (&lt;code&gt;ui.button&lt;/code&gt;) like so:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= link_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Get Started&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, new_user_path, ui.button %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= button_to &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Like&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, likes_path, ui.button %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= submit_tag &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Join&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, ui.button %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= form.submit &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Update&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, ui.button %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is preferable to “button” component as it enables developers to use the familiar Rails APIs they’re used to (&lt;code&gt;link_to&lt;/code&gt;, &lt;code&gt;button_to&lt;/code&gt;, etc.) while maintaining consistent styling and behaviours.&lt;/p&gt;
&lt;p&gt;Components work best when they share both elements and attributes; composing attributes works best when the attributes are shared amongst various elements.&lt;/p&gt;
&lt;p&gt;The downside here is that you have to architect your attributes in a separate file. As such, it’s better suited to established APIs, when you’re reasonable confident of the set of attributes and how they fit into the broader UI.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The explicit repetitiveness of Tailwind’s classes pushes developers to look for ways improve their code structure. Combining Tailwind classes into single compound classes (like &lt;code&gt;.nav-link&lt;/code&gt;) only reduces HTML &lt;code&gt;class&lt;/code&gt; repetition—not repetition in the HTML, and exploring other approaches may reveal better ways to model the user interface.&lt;/p&gt;
&lt;p&gt;My first thought to tidy repetitive Tailwind classes was to use ActionView::Attributes. It’s a flexible approach, and very good for sharing attributes amongst different elements. However, when examining the benefits of a loop, it’s probably a better fit for the original problem. Its extensibility helps guide you towards a more structured approach to their UI, and provides options as the code grows.&lt;/p&gt;
&lt;p&gt;However, I’d encourage developers to tolerate a level of messiness. Only commit to a lower-repetition approach when it hurts to maintain consistent styles. That way you have a better understanding of the problem and can make a more informed decision as to the best approach.&lt;/p&gt;
&lt;p&gt;See also: &lt;a href=&quot;https://x.com/adamwathan/status/1308944904786268161/photo/1&quot;&gt;Adam Wathan’s flowchart for deciding when to extract a component with &lt;code&gt;@apply&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Mon, 01 Jul 2024 21:23:28 GMT</pubDate></item><item><title>Hotwire Back Button</title><link>https://domchristie.co.uk/posts/hotwire-back-button-2024-05-12/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/hotwire-back-button-2024-05-12/</guid><description>&lt;p&gt;A Stimulus back button for full-screen progressive web apps (where the browser’s own back button is not visible), or wherever you need back functionality within your own user interface.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;/dashboard&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-controller&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;navigation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-action&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;navigation#back&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;data-turbo-action&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;Back&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { Controller } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@hotwired/stimulus&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;NavigationController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Controller&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;back&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.#shouldRestore) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      event.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;preventDefault&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      window.history.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;back&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; #&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;shouldRestore&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.#isFirstHistoryEntry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; #&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;isFirstHistoryEntry&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;window.history.state.turbo &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      window.history.state.turbo.restorationIndex &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a user navigates from page-to-page within your Turbo-driven app, this back button (or link) behaves just like a browser back button, taking the user back to where they came from.&lt;/p&gt;
&lt;p&gt;When a user arrives at a page from an external site, this back button visits the link’s URL, replacing the browser’s history entry, leading to a consistent information architecture.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This works by using Turbo’s history state. We can determine if the current page is the first visited page when the user lands on our app. If it is, we need to follow the back button’s URL, keeping the user within our app; otherwise we can just traverse the history.&lt;/p&gt;
&lt;p&gt;What’s more, this works even if the page is reloaded: history state is preserved across reloads (🤯). So if a user navigates and reloads, we can still determine how this back button should behave as before.&lt;/p&gt;</description><pubDate>Sun, 12 May 2024 11:08:45 GMT</pubDate></item><item><title>Turbo Teapot</title><link>https://domchristie.co.uk/posts/turbo-teapot/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/turbo-teapot/</guid><description>&lt;p&gt;&lt;em&gt;You probably shouldn’t do this, but anyway…&lt;/em&gt; I’ve been upgrading an app from Turbolinks to Turbo, and there are a number of controller actions that &lt;code&gt;render&lt;/code&gt; successful responses after form submissions. Turbo expects the server to return an HTTP &lt;code&gt;303 See Other&lt;/code&gt; response in these cases, so returning &lt;code&gt;2xx&lt;/code&gt; won’t render anything. However, Turbo does render error responses (&lt;code&gt;4xx&lt;/code&gt; and &lt;code&gt;5xx&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The HTTP status &lt;code&gt;418 I&apos;m a teapot&lt;/code&gt; was an April Fools’ joke, so it’s basically nonsense, but we can use it as a temporary workround for Turbo’s requirements. For example:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;PostsController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; @post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Post&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.create(post_params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      render &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;status:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (request.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream? &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;418&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:created&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      render &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;status:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:unprocessable_entity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My colleague Sam Oliver suggested wrapping this up in a patch, which ended up looking like this:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# lib/render_418_for_turbo.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Render418ForTurbo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;args)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;[Render418ForTurbo]: Responding with 418 status to work around Turbo&apos;s rendering limitation.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;request.get? &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; request.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; options &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; args.find { |arg| arg.is_a?(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Hash&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;unless&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; options[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:status&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;puts&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; message &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# or my_logger.info message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          options[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:status&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;418&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;puts&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; message &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# or my_logger.info message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        args.push(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;status:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;418&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;super&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# app/controllers/application_controller.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ActionController::Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;prepend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Render418ForTurbo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This patch adds a &lt;code&gt;418&lt;/code&gt; statuses for non-&lt;code&gt;GET&lt;/code&gt; requests that were made via Turbo. It will only add the status if a status is not present, and will log the override.&lt;/p&gt;</description><pubDate>Sun, 05 May 2024 14:38:50 GMT</pubDate></item><item><title>Turbo &amp; Progressive Enhancement</title><link>https://domchristie.co.uk/posts/turbo-progressive-enhancement/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/turbo-progressive-enhancement/</guid><description>&lt;p&gt;Before jumping into composing Turbo Streams or wrapping elements in Turbo Frames, consider what the experience might be without any JavaScript or Hotwire. While a no-JS flow may not be commonly experienced, thinking in this way can lead to cleaner, more robust solutions.&lt;/p&gt;
&lt;p&gt;Let’s say we have a button that toggles a post’s &lt;code&gt;publish&lt;/code&gt; column, and we want to update the screen in-place. Our response could just return the user back to the page they were on, with the button updated:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Post::PublishesController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Post&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:post_id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    post.publish!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    redirect_back_or_to post, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;status:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:see_other&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;destroy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Post&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:post_id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    post.unpublish!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    redirect_back_or_to post, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;status:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:see_other&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would work without any JavaScript, but if the user had scrolled the page, their scroll position would be reset.&lt;/p&gt;
&lt;h2 id=&quot;enhance&quot;&gt;Enhance!&lt;/h2&gt;
&lt;p&gt;The simplest enhancement is to maintain the user’s scroll position by adding &lt;code&gt;&amp;#x3C;meta name=&quot;turbo-refresh-scroll&quot; content=&quot;preserve&quot;&gt;&lt;/code&gt; to the &lt;code&gt;&amp;#x3C;head&gt;&lt;/code&gt;. We don’t need to change any controller code, everything is handled by Turbo. What’s more, if the UI augments over time and includes more elements that require dynamic updates (e.g. a published post count), we don’t need to account for them in our response since the entire content is refreshed. (Compare with Turbo Stream actions that may require modification with each UI change.)&lt;/p&gt;
&lt;p&gt;Next, if we need to preserve more of the UI state, we could morph the refresh by adding &lt;code&gt;&amp;#x3C;meta name=&quot;turbo-refresh-method&quot; content=&quot;morph&quot;&gt;&lt;/code&gt; to the &lt;code&gt;&amp;#x3C;head&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A final benefit of this code is that it’s usable in different contexts. &lt;code&gt;redirect_back_or_to&lt;/code&gt; is really handy for these situations. We can create a publish toggle button on another page, point it to this controller, and it will work in the same way—again without having to add or change any controller code, or fiddle about with Turbo Stream actions.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Concepts demonstrated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle&quot;&gt;Open-closed principle&lt;/a&gt;: our UI is open for extension without having to modify existing controller code&lt;/li&gt;
&lt;li&gt;Sandi Metz’s &lt;abbr title=&quot;Transparent, Reasonable, Useful, and Exemplary&quot;&gt;TRUE&lt;/abbr&gt; principles from &lt;a href=&quot;https://sandimetz.com/products&quot;&gt;Practical Object-Oriented Design&lt;/a&gt;: our controller action is &lt;em&gt;Useful&lt;/em&gt; in different contexts&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Sun, 28 Apr 2024 08:21:00 GMT</pubDate></item><item><title>Turbo Refreshes, Frames, and Streams</title><link>https://domchristie.co.uk/posts/turbo-refreshes-frames-streams/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/turbo-refreshes-frames-streams/</guid><description>&lt;p&gt;A guide for when to use each Turbo feature.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/turbo-streams-frames-refreshes.png&quot; alt=&quot;A flow diagram containing the considerations for when to use each Turbo feature. To summarise: if the page response only makes a small number of changes, use Turbo Streams; otherwise, if the response updates a distinct area of the page, use Turbo Frames; otherwise, use a Turbo Refresh. If the update requires that lots of UI state is to be kept (e.g. live input values), use a Morph refresh, otherwise a plain Replace Refresh will do.&quot;&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;turbo-refreshes&quot;&gt;Turbo Refreshes&lt;/h2&gt;
&lt;p&gt;Turbo Refreshes update the entire current page in place while keeping some UI state e.g. the page’s scroll position. This might seem like overkill in some cases and they’re slower that Turbo Streams, but they can really simplify response code (and the performance hit may not matter anyway).&lt;/p&gt;
&lt;p&gt;Refreshes let you customise whether the page’s scroll position is reset or preserved, and/or whether the page’s content is replaced or “morphed”. The simplest refresh enhancement just maintains the scroll position and replaces the content:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# With Ruby on Rails %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= turbo_refreshes_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;scroll:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:preserve&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# or with plain HTML in the &amp;#x3C;head&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;turbo-refresh-scroll&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;preserve&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;morphs&quot;&gt;Morphs&lt;/h3&gt;
&lt;p&gt;For advanced cases you can also “morph” the page’s content. This updates only the elements that have changed, leaving the rest untouched. Morphing is useful when you need to maintain UI state such as the content of input fields, element scroll positions, or if you’re remotely updating another connected client via a broadcasted (Web Socket) Turbo Stream.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# With Ruby on Rails %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= turbo_refreshes_with &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;scroll:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:preserve&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;method:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:morph&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# or with plain HTML in the &amp;#x3C;head&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;turbo-refresh-scroll&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;preserve&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;turbo-refresh-method&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;morph&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Morphs can reset elements to their server state, reverting changes that have been made locally. Fixing these issues may require knowledge of DOM-diffing algorithms. &lt;a href=&quot;https://turbo.hotwired.dev/handbook/page_refreshes#exclude-sections-from-morphing&quot;&gt;&lt;code&gt;data-turbo-permanent&lt;/code&gt;&lt;/a&gt; provides a solution to opt-out of morphing for those elements, but dotting this around arbitrarily feels like a bit of a code-smell.&lt;/p&gt;
&lt;h2 id=&quot;turbo-frames&quot;&gt;Turbo Frames&lt;/h2&gt;
&lt;p&gt;Use Turbo Frames for parts of the page that have a distinct independent context. This becomes clearer with experience, but their features provide some hints. Turbo Frame contents are &lt;em&gt;navigable&lt;/em&gt; from links and forms, and they can be loaded asynchronously from the rest of the page load. If you don’t feel your interface benefits from these features, then consider a Refresh or Streams.&lt;/p&gt;
&lt;h2 id=&quot;turbo-streams&quot;&gt;Turbo Streams&lt;/h2&gt;
&lt;p&gt;Turbo Streams are inviting because they fit a simple procedural mindset: &lt;em&gt;“when I press this button, I want to update X, Y, and Z”&lt;/em&gt;. However this can easily escalate, and your responses become an unstructured mess of arbitrary Turbo Stream actions. If you’re rendering more than a few Turbo Stream actions, consider Frames or Refreshes.&lt;/p&gt;
&lt;p&gt;To update multiple clients in realtime, you’ll need to broadcast a Turbo Stream over a Web Socket connection. The same principles diagrammed above apply in this case too: if the response makes multiple updates, broadcast a Turbo Stream Refresh, otherwise broadcast Turbo Stream actions.&lt;/p&gt;</description><pubDate>Sun, 21 Apr 2024 10:15:00 GMT</pubDate></item><item><title>Art We Are Drawn To</title><link>https://domchristie.co.uk/posts/art-we-are-drawn-to-2024-03-02/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/art-we-are-drawn-to-2024-03-02/</guid><description>&lt;blockquote&gt;&lt;p&gt;[T]he art that people are drawn to–at an individual and collective level–reflects much about what is missing from their lives. The particular register of emotions we&apos;re sensitive to in the visual sphere hints at what we long for, but don&apos;t reliably have a connection to, in ourselves.&lt;/p&gt;&lt;cite&gt;The Good Enough Parent 2021, p.83&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Sat, 02 Mar 2024 10:06:44 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2024-03-01/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2024-03-01/</guid><description>&lt;p&gt;To have a scrollable element scroll to the bottom by default (CSS only, without JavaScript), use &lt;code&gt;display: flex; flex-direction: column-reverse&lt;/code&gt;. Via &lt;a href=&quot;https://stackoverflow.com/a/44051405&quot;&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Fri, 01 Mar 2024 08:43:04 GMT</pubDate></item><item><title>Enhance Music</title><link>https://domchristie.co.uk/posts/enhance-music/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/enhance-music/</guid><description>&lt;p&gt;&lt;a href=&quot;https://begin.com/blog/posts/2023-09-28-introducing-enhance-music&quot;&gt;Enhance Music&lt;/a&gt; is a clever demonstration of a progressively enhanced music player. The fallback uses links to navigate an &lt;code&gt;iframe&lt;/code&gt; player bar which includes an &lt;code&gt;autoplay&lt;/code&gt; &lt;code&gt;audio&lt;/code&gt; element. It is enhanced with a custom JavaScript-based player that persists between page loads. A great example of &lt;a href=&quot;https://en.wikipedia.org/wiki/Gunpei_Yokoi#Lateral_Thinking_with_Withered_Technology&quot;&gt;lateral thinking with withered technology&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 12 Oct 2023 06:15:00 GMT</pubDate></item><item><title>Tailwind Utopia</title><link>https://domchristie.co.uk/posts/tailwind-utopia/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tailwind-utopia/</guid><description>&lt;p&gt;&lt;a href=&quot;https://github.com/domchristie/tailwind-utopia&quot;&gt;Tailwind Utopia&lt;/a&gt; is a Tailwind CSS plugin for generating fluid type and space scales based on &lt;a href=&quot;https://utopia.fyi/&quot;&gt;Utopia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://utopia.fyi/blog/designing-with-fluid-type-scales&quot;&gt;James Gilyead’s introductory blog post&lt;/a&gt; explains this best, but the idea is that breakpoint-based design feels like creating fixed layouts for an abitrary number of sizes. The Utopia approach encourages designers to design type and space scales for the smallest and largest screens, then let &lt;em&gt;maths&lt;/em&gt; design the sizes inbetween. No breakpoints, just an algorithm that interpolates between the two scales.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://utopia.fyi/space/calculator/&quot;&gt;Utopia’s CSS space generator&lt;/a&gt; creates sizing variables that fluidly scale. For example:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;--space-s&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.125&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.0815&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.2174&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.25&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* 18px-20px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;--space-m&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.6875&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.6223&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.3261&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.875&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* 27px-30px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;--space-l&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2.25&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2.163&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.4348&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2.5&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* 36px-40px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spacing pairs can also be generated, taking the fluid value for the smallest size, and scaling it to a larger value. For example:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;--space-s-m&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.125&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.8641&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.3043&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.875&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* 18px-30px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;--space-s-l&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1.125&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.6467&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2.3913&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2.5&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/* 18px-40px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The benefit of using a CSS generator like Tailwind, is that any number of these spacing pairs can be generated on-the-fly. Simply apply the fluid class names the HTML, and the spacing pair is generated:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;mt-fl-sm-lg&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;Hello, world!&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;!-- fluid margin top from sm-lg --&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So this is what &lt;a href=&quot;https://github.com/domchristie/tailwind-utopia&quot;&gt;Tailwind Utopia&lt;/a&gt; does.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/cwsdigital/tailwind-utopia&quot;&gt;original tailwind-utopia plugin&lt;/a&gt; was developed by &lt;a href=&quot;https://www.chrispymm.co.uk/&quot;&gt;Chris Pymm&lt;/a&gt; and &lt;a href=&quot;https://cwsdigital.com/&quot;&gt;CWS Digital&lt;/a&gt;, and rewritten by me to work with Tailwind’s &lt;abbr title=&quot;just-in-time&quot;&gt;JIT&lt;/abbr&gt; compiler.&lt;/p&gt;</description><pubDate>Mon, 09 Oct 2023 07:32:43 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2023-09-15/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2023-09-15/</guid><description>&lt;p&gt;I have been experimenting with the History API, working out a way to determine the direction of a &lt;code&gt;popstate&lt;/code&gt; event. &lt;code&gt;popstate&lt;/code&gt; is dispatched when navigating Back and Forward, and there’s no direction information in the event. However, reading &lt;a href=&quot;https://github.com/withastro/astro/blob/fca6892f8d6a30ceb1e04213be2414dd4cb4d389/packages/astro/components/ViewTransitions.astro#L433&quot;&gt;Astro’s View Transition code&lt;/a&gt;, I noticed that &lt;a href=&quot;https://github.com/matthewp&quot;&gt;Matthew Phillips&lt;/a&gt; had implemented this by storing an index in the History state, and keeping track of the current index on &lt;code&gt;history.pushState&lt;/code&gt;. The direction can be then determined by comparing the current index with the index from the popstate event.&lt;/p&gt;
&lt;p&gt;What was most surprising was the following:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (history.state) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// we reloaded a page with history state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// (e.g. history navigation from non-transition page or browser reload)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It turns out that the History state is persisted between page refreshes:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;history.state &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;history.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;pushState&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({ index: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; }, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;history.state.index &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;location.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;reload&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;history.state.index &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Fri, 15 Sep 2023 08:24:53 GMT</pubDate></item><item><title>UI Context and Rails Variants</title><link>https://domchristie.co.uk/posts/ui-context-and-rails-variants/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/ui-context-and-rails-variants/</guid><description>&lt;p&gt;This is a follow-up to &lt;a href=&quot;/posts/scoping-controllers-by-ui-context/&quot;&gt;Scoping Rails Controllers by UI Context&lt;/a&gt;, where I suggested a controller architecture for handling the same action in multiple contexts.&lt;/p&gt;
&lt;p&gt;For example, in Apple’s iOS Mail app, you can delete a message in at least 3 different places: when reading the message itself, by swiping in a list, or deleting via a context menu. In each case, the code to delete the message might be the same, but the visual response differs.&lt;/p&gt;
&lt;p&gt;The previous post suggested a 1:1 mapping between routes and controller actions to handle each case, scoped by the UI context:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DELETE /messages/:id =&gt; messages#destroy&lt;/code&gt; (default case)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /list_items/messages/:id =&gt; list_items/messages#destroy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /context_menus/messages/:id =&gt; context_menus/messages#destroy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The deletion code could be shared through inheritance or composition, but the responses would vary.&lt;/p&gt;
&lt;h2 id=&quot;variants&quot;&gt;Variants&lt;/h2&gt;
&lt;p&gt;After I shared this on &lt;a href=&quot;http://discord.gg/NNN3TAD5jQ&quot;&gt;Kasper’s Discord&lt;/a&gt;, &lt;a href=&quot;https://ruby.social/@kaspth&quot;&gt;Kasper&lt;/a&gt; suggested an approach using variants. Rather than a 1:1 mapping of routes to controller actions, Kasper suggested mapping different routes to a single controller action, and switching the response based on the variant. The variant could be sent as a default param and set in the controller. For example, the routes might look as follows:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# config/routes.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Rails&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.application.routes.draw &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  resources &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:messages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  scope &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:list_items&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;as:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:list_items&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;defaults:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;variant:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:list_items&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    resources &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:messages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  scope &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:context_menus&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;as:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:context_menus&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;defaults:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;variant:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:context_menus&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    resources &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:messages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# (Yes, there is repetition here, which could be cleaned up)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this in place, we have the following routes that all map to &lt;code&gt;messages#destroy&lt;/code&gt;, but each has a different &lt;code&gt;params[:variant]&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DELETE /messages/:id =&gt; messages#destroy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /list_items/messages/:id =&gt; messages#destroy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /context_menus/messages/:id =&gt; messages#destroy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The request variant could then be set as follows:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ActionController::Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  before_action &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:set_variant&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;VARIANTS&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:list_items&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:context_menus&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;set_variant&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    request.variant &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:variant&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;].to_sym &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:variant&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;].in?(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;VARIANTS&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here we can customise our responses. We could do this via templates or via a &lt;code&gt;respond_to&lt;/code&gt; call:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;MessagesController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;destroy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message.destroy!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    respond_to &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream.none {…}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream.list_items {…}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream.context_menus {…}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;Overall, I really like the variants approach. Routing different paths to a single controller action feels cleaner and more manageable. I think the only downside is if we needed additional device-specific variants i.e. if we also wanted to render a different context menu on desktop vs mobile, it might be tricky.&lt;/p&gt;</description><pubDate>Thu, 07 Sep 2023 08:35:52 GMT</pubDate></item><item><title>Hotwire &amp; Personalised Content</title><link>https://domchristie.co.uk/posts/hotwire-personalised-content/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/hotwire-personalised-content/</guid><description>&lt;p&gt;Here’s an alternative approach to that which James Adam describes in &lt;a href=&quot;https://goodenough.us/blog/2023-08-02-til-turbo-stream-and-personalised-content/&quot;&gt;TIL: Turbo Stream and personalised content&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To recap the problem: how do you personalise content when rendering from a WebSocket Turbo Stream? The rendering is not in the context of a request, so customisations based on objects like &lt;code&gt;current_user&lt;/code&gt; will fail. For example, consider a chat app where messages should display the author name or “You” when viewing your own messages:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/messages/_message.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&amp;#x3C;%= dom_id(message) %&gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= current_user &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; message.author &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;You&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; : message.author.name %&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= message.body %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;James’s solution is to flag potential customisations in the partial with data attributes, and then conditionally update them using a Stimulus controller.&lt;/p&gt;
&lt;p&gt;We faced the same issue a while back with &lt;a href=&quot;https://pusher.com/&quot;&gt;Pusher&lt;/a&gt; (pre-Hotwire and pre-Action Cable), and my colleague, Sam Oliver, suggested an approach that works around the WebSocket rendering limitation. Here’s how that idea might look with with Hotwire/Turbo.&lt;/p&gt;
&lt;h2 id=&quot;rendering-via-requests&quot;&gt;Rendering via Requests&lt;/h2&gt;
&lt;p&gt;Instead of using the WebSocket Turbo Stream to append newly created messages directly, we’ll use it to instruct each client to make an HTTP request to &lt;code&gt;messages#show&lt;/code&gt;. The response will be a Turbo Stream that appends the new message. The partial renderer now has access to a user-specific request, and can make personalisations as needed.&lt;/p&gt;
&lt;p&gt;First, we’ll create our &lt;a href=&quot;https://turbo.hotwired.dev/handbook/streams#custom-actions&quot;&gt;custom Turbo Stream action&lt;/a&gt;. It includes the &lt;code&gt;fetch&lt;/code&gt; action attribute and the URL to fetch&lt;sup&gt;&lt;a href=&quot;#fn1&quot; id=&quot;r1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/application/_fetch.turbo_stream.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;turbo-stream&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;fetch&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&amp;#x3C;%= url_for(url) %&gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;turbo-stream&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The custom action JavaScript below creates a link with the given &lt;code&gt;url&lt;/code&gt; attribute. This link includes a &lt;code&gt;data-turbo-stream&lt;/code&gt; attribute to trigger a Turbo Stream response. It’s appended to the body, programmatically clicked, then removed.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// app/javascript/application.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { Turbo } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@hotwired/turbo&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// &amp;#x3C;turbo-stream action=&quot;fetch&quot; url=&quot;/messages/1&quot;&gt;&amp;#x3C;/turbo-stream&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Turbo.StreamActions.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;fetcher&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;createElement&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  fetcher.href &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;getAttribute&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;url&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  fetcher.dataset.turboStream &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  document.body.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;appendChild&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(fetcher)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  fetcher.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  document.body.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;removeChild&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(fetcher)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we’ll update the model to broadcast the custom &lt;code&gt;fetch&lt;/code&gt; action:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationRecord&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  after_create_commit &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    broadcast_render_to(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:messages&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;partial:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;fetch&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;locals:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;url:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we’ll add a &lt;code&gt;messages#show&lt;/code&gt; action that appends the message:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;MessagesController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;show&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# authorize current_user can read message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# app/views/messages/show.turbo_stream.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= turbo_stream.append &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:messages&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, render(@message) %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To summarise this flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user sends a message&lt;/li&gt;
&lt;li&gt;A custom WebSocket Turbo Stream &lt;code&gt;fetch&lt;/code&gt; action is transmitted to all connected clients&lt;/li&gt;
&lt;li&gt;This action instructs each client to make a Turbo Stream HTTP request to the given message URL&lt;/li&gt;
&lt;li&gt;The response appends the message partial using &lt;code&gt;turbo_stream.append&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this way, there’s no need to duplicate rendering logic in a Stimulus controller; all personalisation is declared in the message partial.&lt;/p&gt;
&lt;h2 id=&quot;downsides&quot;&gt;Downsides&lt;/h2&gt;
&lt;p&gt;The main downside is that it incurs additional HTTP round-trips. To the sender of the message, it might feel a little laggy. In our own Pusher-based app, we append the user’s message via the &lt;code&gt;messages#create&lt;/code&gt; response, and only stream the fetch action to the recipient&lt;sup&gt;&lt;a href=&quot;#fn2&quot; id=&quot;r2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, which helps it feel snappier. The delay in appending the message could be remedied in other ways, e.g. with improved loading feedback, or even an optimistic update, whereby the message is provisionally appended on the client and then updated.&lt;/p&gt;
&lt;p&gt;These additional requests will also impact the load on the server. For most cases, this probably won’t be a problem, but at larger scales with many connected users, this might be a consideration.&lt;/p&gt;
&lt;hr&gt;
&lt;p id=&quot;fn1&quot; class=&quot;text-fl-sm&quot;&gt;&lt;a class=&quot;after:content-[&amp;#x27;⤴&amp;#x27;]&quot; href=&quot;#r1&quot;&gt;[1]&lt;/a&gt; Using &lt;a href=&quot;https://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for&quot;&gt;&lt;code&gt;url_for&lt;/code&gt;&lt;/a&gt; means &lt;code&gt;url&lt;/code&gt; can be either a string or Active Record object (or any other object that &lt;code&gt;url_for&lt;/code&gt; supports). It’s particularly useful in our case as we can generate a URL for the newly created &lt;code&gt;Message&lt;/code&gt; in our model, without having to call a URL helper.&lt;/p&gt;
&lt;p id=&quot;fn2&quot; class=&quot;text-fl-sm&quot;&gt;&lt;a class=&quot;after:content-[&amp;#x27;⤴&amp;#x27;]&quot; href=&quot;#r2&quot;&gt;[2]&lt;/a&gt; Pusher has a feature that can filter out user-sent events, so the fetch event is not broadcast to the user and therefore the message does not get appended twice.&lt;/p&gt;</description><pubDate>Wed, 06 Sep 2023 08:05:10 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2023-08-16/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2023-08-16/</guid><description>&lt;p&gt;In Ruby, curly braces can be omitted from hashes not only when the hash is the last argument of a method, but also when it’s the last item in an array: &lt;code&gt;[1, 2, three: :four]&lt;/code&gt;. Neat!&lt;/p&gt;</description><pubDate>Wed, 16 Aug 2023 16:32:14 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2023-08-14/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2023-08-14/</guid><description>&lt;p&gt;Rails’ &lt;a href=&quot;https://api.rubyonrails.org/classes/Array.html#method-i-inquiry&quot;&gt;&lt;code&gt;Array#inquiry&lt;/code&gt;&lt;/a&gt; makes checking string-like arrays easier (via Kasper Timm Hansen):&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# instead of:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;parts &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:feed&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:description&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:play&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:play_later&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;parts.include?(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:description&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# with `inquiry`:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;parts &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:feed&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:description&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:play&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:play_later&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;].inquiry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;parts.description?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rails’ &lt;a href=&quot;https://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-truncate&quot;&gt;&lt;code&gt;truncate&lt;/code&gt;&lt;/a&gt; helper accepts a block which is captured and displayed when the contents is truncated. (via &lt;a href=&quot;https://twitter.com/_swanson/status/1356041464078364679.&quot;&gt;Matt Swanson on Twitter&lt;/a&gt;)&lt;/p&gt;</description><pubDate>Mon, 14 Aug 2023 18:46:55 GMT</pubDate></item><item><title>Scoping Rails Controllers by UI Context</title><link>https://domchristie.co.uk/posts/scoping-controllers-by-ui-context/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/scoping-controllers-by-ui-context/</guid><description>&lt;p&gt;Rails’ generators encourage developers to think about their controllers in terms of domain models. Running &lt;code&gt;rails generate resource Message …&lt;/code&gt; will create the &lt;code&gt;Message&lt;/code&gt; model along with a &lt;code&gt;MessagesController&lt;/code&gt;. This setup works for simple cases, but when our user interfaces become more complex, trying to stuff all our actions into the &lt;code&gt;MessagesController&lt;/code&gt; can lead to unmaintainable fat controllers.&lt;/p&gt;
&lt;h2 id=&quot;example-deleting-in-different-contexts&quot;&gt;Example: Deleting in Different Contexts&lt;/h2&gt;
&lt;p&gt;Consider how we might model deleting a message in Apple’s iOS Mail app. There are at least 3 ways to delete a single message:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tapping the trash icon in the toolbar when viewing the message&lt;/li&gt;
&lt;li&gt;Swiping on the message in a list&lt;/li&gt;
&lt;li&gt;Long-pressing on the message in a list to bring up a context menu&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;grid gap-fl-xs grid-cols-[repeat(auto-fit,minmax(16rem,1fr))]&quot;&gt;
  &lt;figure class=&quot;!m-0&quot;&gt;
    &lt;img src=&quot;/message-delete-show.PNG&quot; width=&quot;563&quot; height=&quot;200&quot;&gt;
    &lt;figcaption&gt;
      Deleting a message when viewing it
    
  &lt;/figcaption&gt;&lt;/figure&gt;
  &lt;figure class=&quot;!m-0&quot;&gt;
    &lt;img src=&quot;/message-delete-list-item.PNG&quot; width=&quot;563&quot; height=&quot;200&quot;&gt;
    &lt;figcaption&gt;
      Deleting by swiping
    
  &lt;/figcaption&gt;&lt;/figure&gt;
  &lt;figure class=&quot;!m-0&quot;&gt;
    &lt;img src=&quot;/message-delete-context-menu.PNG&quot; width=&quot;563&quot; height=&quot;200&quot;&gt;
    &lt;figcaption&gt;
      Deleting via a context menu
    
  &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Each case deletes a message, but the visual outcomes vary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when viewing the message, deleting removes the entire message, then displays the next message in the list&lt;/li&gt;
&lt;li&gt;swiping removes the list item in place&lt;/li&gt;
&lt;li&gt;deleting via the context menu hides the menu then removes the list item in place&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Handling the first case is straightforward. We could display the trash button on our &lt;code&gt;show&lt;/code&gt; view which destroys the record. Our &lt;code&gt;MessagesController#destroy&lt;/code&gt; action could handle that:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;MessagesController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @messages &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;show&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;destroy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message.destroy!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    redirect_to next_message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; messages_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;private&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;next_message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      .where(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;created_at &amp;#x3C; ?&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, @message.created_at)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      .order(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;created_at:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:desc&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      .first&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the other cases, there are few approaches.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;See the follow up: &lt;a href=&quot;/posts/ui-context-and-rails-variants/&quot;&gt;UI Context and Rails Variants&lt;/a&gt; for a rethink on the below approach.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, we might be tempted to reuse and expand our &lt;code&gt;destroy&lt;/code&gt; action by switching the response based on the context. We could achieve this by setting a &lt;code&gt;context&lt;/code&gt; param on our destroy form.&lt;/p&gt;
&lt;p&gt;Alternatively we might choose to add further actions to our &lt;code&gt;MessagesController&lt;/code&gt; (e.g.&lt;code&gt;destroy_in_list&lt;/code&gt; or &lt;code&gt;destroy_in_context_menu&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In my experience, these approaches lead to unsatisfactory solutions. Switch statements become unwieldy and hard to test, or view directories become filled with unconventional templates. Both feel messy.&lt;/p&gt;
&lt;h2 id=&quot;restful-nesting&quot;&gt;RESTful Nesting&lt;/h2&gt;
&lt;p&gt;When modelling user interfaces, I’ve found that sticking to &lt;a href=&quot;http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/&quot;&gt;RESTful actions with nested controllers&lt;/a&gt; works nicely, i.e. favouring &lt;code&gt;index&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;destroy&lt;/code&gt; over custom actions, and nesting controllers in order to do so. This approach helps maintain a standard list of actions and templates and can aid with the discovery of other presentation objects.&lt;/p&gt;
&lt;p&gt;When considering top-level naming, again, it’s tempting to stick to domain object names, e.g. &lt;code&gt;Inboxes::&lt;wbr&gt;MessagesController&lt;/code&gt;, but this would not help us much in the example above. Messages in the inbox can be deleted in at least two ways: by swiping, as well as from the context menu, so we’d still need two &lt;code&gt;destroy&lt;/code&gt; actions.&lt;/p&gt;
&lt;p&gt;One approach I’ve been considering is scoping by UI context. For example we could add a &lt;code&gt;ListItems::&lt;wbr&gt;MessagesController&lt;/code&gt; and a &lt;code&gt;ContextMenus::&lt;wbr&gt;MessagesController&lt;/code&gt;. Each response could update the UI as required:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ListItems::&lt;wbr&gt;MessagesController#&lt;wbr&gt;destroy&lt;/code&gt; could remove message list item&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContextMenus::&lt;wbr&gt;MessagesController#&lt;wbr&gt;destroy&lt;/code&gt; could remove the context menu and message&lt;/li&gt;
&lt;/ul&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# app/controllers/list_items/messages_controller.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ListItems::MessagesController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;destroy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message.destroy!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    respond_to &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.html { redirect_to messages_path }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# app/controllers/context_menus/messages_controller.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ContextMenus::MessagesController&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;destroy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @message.destroy!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    respond_to &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.html { redirect_to messages_path }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This feels nice for a couple of reasons.&lt;/p&gt;
&lt;p&gt;First, you see a pattern emerge in these two actions—their code is identical. The only difference exists between the &lt;code&gt;turbo_stream&lt;/code&gt; templates. Once we’re confident that this pattern is is solid, we could extract it into a concern. The concern could even handle any &lt;code&gt;ActiveRecord&lt;/code&gt; type by inferring the class and redirect-path from the controller name (see &lt;a href=&quot;#appendix&quot;&gt;Appendix&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Second, it paves the way for other resources to follow the same pattern. A top-level &lt;code&gt;ListItems&lt;/code&gt; or &lt;code&gt;ContextMenus&lt;/code&gt; namespace clarifies where subsequent controllers should live, and it’s clearer than hiding a &lt;code&gt;context&lt;/code&gt; parameter in a form, or implementing custom action names.&lt;/p&gt;
&lt;h2 id=&quot;scope-by-ui-context-or-domain-object&quot;&gt;Scope by UI Context or Domain Object?&lt;/h2&gt;
&lt;p&gt;Should it be &lt;code&gt;ListItems::&lt;wbr&gt;MessagesController&lt;/code&gt; or &lt;code&gt;Messages::&lt;wbr&gt;ListItemsController&lt;/code&gt;? For the deletion case, I prefer &lt;code&gt;ListItems::&lt;wbr&gt;MessagesController&lt;/code&gt;: we’re destroying the message in the context of a list item, not the other way round. As mentioned above, it also clarifies the organisation for future list item controls.&lt;/p&gt;
&lt;p&gt;However, for actions such as &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;show&lt;/code&gt;, it doesn’t work quite so well. For example, let’s say we wanted an endpoint to render a context menu in a Turbo Frame, and we used &lt;code&gt;ContextMenus::&lt;wbr&gt;MessagesController#&lt;wbr&gt;show&lt;/code&gt; to do so. This organisation communicates that this action &lt;em&gt;shows a message in the context of a list item&lt;/em&gt;. As we’re showing a context menu with a list of actions, this framing is a bit of a stretch. &lt;code&gt;Messages::&lt;wbr&gt;ContextMenusController#&lt;wbr&gt;show&lt;/code&gt; might be preferrable in this case, or we could add another layer of nesting: &lt;code&gt;ContextMenus::&lt;wbr&gt;Messages::&lt;wbr&gt;ActionsController#&lt;wbr&gt;index&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It’s still early days with this approach. I think I still prefer &lt;code&gt;ContextMenus::&lt;wbr&gt;MessagesController#&lt;wbr&gt;show&lt;/code&gt;, and deal with how it might be a bit of a stretch, but I’ll see how it goes…&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Finally, for UI context naming inspiration, check out &lt;a href=&quot;https://developer.apple.com/design/human-interface-guidelines/&quot;&gt;Apple’s Human Interface Guidelines&lt;/a&gt;, particularly &lt;a href=&quot;https://developer.apple.com/design/human-interface-guidelines/menus-and-actions&quot;&gt;Menus and Actions&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;appendix&quot;&gt;Appendix&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;Destroyable&lt;/code&gt; controller concern with a &lt;code&gt;destroy&lt;/code&gt; action that destroys a record and renders a corresponding &lt;code&gt;turbo_stream&lt;/code&gt; or redirects.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# app/controllers/concerns/destroyable.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Destroyable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Concern&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;destroy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @resource &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; resource_class.find(params[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    @resource.destroy!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    respond_to &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.turbo_stream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.html { redirect_to send(fallback_path) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;private&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;resource_class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    controller_name.classify&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fallback_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;#{controller_name}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;_path&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Sat, 12 Aug 2023 16:00:32 GMT</pubDate></item><item><title>Bricolage</title><link>https://domchristie.co.uk/posts/bricolage/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/bricolage/</guid><description>&lt;p&gt;&lt;a href=&quot;https://ateliertriay.github.io/bricolage/&quot;&gt;Bricolage&lt;/a&gt; looks great: &lt;q&gt;A free and open source variable font with French attitude and British mannerisms across 3 axis: weight, width &amp;#x26; optical size&lt;/q&gt;&lt;/p&gt;</description><pubDate>Fri, 11 Aug 2023 12:05:22 GMT</pubDate></item><item><title>Ruby Emoji</title><link>https://domchristie.co.uk/posts/ruby-emoji/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/ruby-emoji/</guid><description>&lt;p&gt;Ruby’s Regexp character properties provides a nice way to check for emoji characters:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;👍&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.match?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D; font-weight: bold&quot;&gt;\p&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;{Emoji}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, to check if a string consists entirely of emoji, the following does not work:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;❤️👍&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.match?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;^(&lt;/span&gt;&lt;span style=&quot;color: #85E89D; font-weight: bold&quot;&gt;\p&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;{Emoji})$&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# ⁉️&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;❤️ is a compound emoji consisting of two characters: U+2764 (emoji), and a modifier U+FE0F (not emoji). So perform this check accurately, we use the &lt;code&gt;grapheme_clusters&lt;/code&gt; string method. As implied, this splits the string into clusters of characters including their modifiers:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;❤️👍&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.grapheme_clusters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;❤️&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;👍&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Modifiers come after the initial emoji, so if we check each cluster starts with an emoji we achieve the expected result:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;❤️👍&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.grapheme_clusters.all? { |e| e.match?(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #85E89D; font-weight: bold&quot;&gt;\p&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF&quot;&gt;{Emoji}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Tue, 27 Jun 2023 20:39:16 GMT</pubDate></item><item><title>Apple Podcasts to OPML</title><link>https://domchristie.co.uk/posts/apple-podcasts-opml/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/apple-podcasts-opml/</guid><description>&lt;p&gt;Here’s &lt;a href=&quot;https://www.icloud.com/shortcuts/5e49239698c44e92baf94399df86b3f9&quot;&gt;an Apple Shortcut (for iOS &amp;#x26; macOS) that exports podcast subscriptions to an OPML file&lt;/a&gt;, making it easier to switch away from Apple’s default Podcast app. It’s based on the &lt;a href=&quot;https://www.icloud.com/shortcuts/68ca7952a5374d4c8fa129e3db3798b9&quot;&gt;Shortcut created by Pocket Casts&lt;/a&gt; (thanks!), but skips the importing part and instead just downloads the file.&lt;/p&gt;</description><pubDate>Mon, 17 Apr 2023 08:57:04 GMT</pubDate></item><item><title>Dynamic Viewport Height in Tailwind</title><link>https://domchristie.co.uk/posts/tailwind-dvh/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tailwind-dvh/</guid><description>&lt;p&gt;I’m sure Tailwind will soon support &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/length#relative_length_units_based_on_viewport&quot;&gt;Dynamic Viewport Units&lt;/a&gt; but in the meantime, here’s a plugin that generates &lt;code&gt;.min-h-dscreen&lt;/code&gt;/&lt;code&gt;.h-dscreen&lt;/code&gt; utilities. Values use &lt;code&gt;100dvh&lt;/code&gt; but fall back to &lt;code&gt;-webkit-fill-available&lt;/code&gt; or environment calculations.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// tailwind.config.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;plugin&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;tailwindcss/plugin&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  plugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;plugin&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;addUtilities&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;addUtilities&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;.min-h-dscreen&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;minHeight&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;.h-dscreen&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;height&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;property&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          [property]: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;calc(100vh - env(safe-area-inset-bottom, 0) - env(safe-area-inset-top, 0))&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;100dvh&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;@supports (-webkit-touch-callout: none)&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;            [property]: [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;-webkit-fill-available&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;100dvh&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;example-output&quot;&gt;Example Output&lt;/h2&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;.min-h-dscreen&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;min-height&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;vh&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; env(safe-area-inset-bottom, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) - env(safe-area-inset-top, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;min-height&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;dvh&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;@supports&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;-webkit-touch-callout&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;.min-h-dscreen&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;min-height&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;-webkit-fill-available&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;min-height&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;dvh&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inspired by the &lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss/discussions/4515#discussioncomment-2112460&quot;&gt;discussion on -webkit-fill-available&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Fri, 10 Mar 2023 12:18:46 GMT</pubDate></item><item><title>Pursuing Happiness</title><link>https://domchristie.co.uk/posts/pursuing-happiness/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/pursuing-happiness/</guid><description>&lt;p&gt;I really enjoyed the recent Hidden Brain episode, &lt;a href=&quot;https://hiddenbrain.org/podcast/happiness-2-0-the-path-to-contentment/&quot;&gt;Happiness 2.0: The Path to Contentment&lt;/a&gt;. It discusses how focussing on attaining happiness can be damaging. The John Stuart Mill quotation referenced, summarised this perfectly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ask yourself whether you are happy and you cease to be so.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The research of Mihaly Csikszentmihalyi into &lt;em&gt;flow&lt;/em&gt; is also mentioned. People experienced feelings of deep happiness after a period of flow, suggesting that when we lose track of our &lt;strong&gt;self&lt;/strong&gt;, we open ourself up to being happy; and conversely, when we check in with ourselves, that sense of happiness can be interrupted.&lt;/p&gt;
&lt;p&gt;Psychologist &lt;a href=&quot;https://psychology.berkeley.edu/people/iris-mauss&quot;&gt;Iris Mauss&lt;/a&gt; referenced another John Stuart Mill quotation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Those only are happy who have their minds fixed on some object other than their own happiness. On the happiness of others, on the improvement of mankind, even on some art or pursuit followed not as a means, but as itself an ideal end. Aiming thus at something else, they find happiness by the way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mauss also suggests a mindset of acceptance and approaching situations with &lt;em&gt;preferences&lt;/em&gt; rather than &lt;em&gt;necessities&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think one overall recommendation is to have an accepting mindset for both our negative and our positive emotions. Don’t monitor as much, don’t try to avoid, don’t try to strive too much for something else. One way to think about this is that it replaces a mindset of “I need to be” with a mindset of “I prefer”. I think we can still have preferences. The problems come in where we tell ourselves, “I must feel a certain way or else I can’t have a good life.” That’s, I think, what we need to avoid. Preferences with a light touch are good for our mental health and well-being. It’s the need and the concern that we want to get away from.&lt;/p&gt;
&lt;/blockquote&gt;</description><pubDate>Fri, 10 Mar 2023 08:26:14 GMT</pubDate></item><item><title>Apps We Spend Our Time On</title><link>https://domchristie.co.uk/posts/apps-we-spend-our-time-on/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/apps-we-spend-our-time-on/</guid><description>&lt;blockquote&gt;&lt;p&gt;If all you ever eat is the factory-farmed fast food, you are not going to feel good. The things we remember in our lives are those great meals we had, surrounded by people we love, &lt;em&gt;made&lt;/em&gt; by people who love us, that was a cuisine that was part of our community, or part of our culture, part of our tradition.&lt;/p&gt;&lt;p&gt;The same thing could be true of the web we spend our time on; what if an app or site that we use every day, was made by somebody we know that we love, that&apos;s part of a community that we&apos;re a part of, was &lt;em&gt;made by people we can name&lt;/em&gt;? How many apps on your phone were made by somebody you know who made it? Not enough.&lt;/p&gt;&lt;cite&gt;Anil Dash on &lt;a href=&quot;https://daringfireball.net/thetalkshow/2022/11/18/ep-362&quot;&gt;The Talk Show&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Sun, 04 Dec 2022 11:15:57 GMT</pubDate></item><item><title>Partials</title><link>https://domchristie.co.uk/posts/partials/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/partials/</guid><description>&lt;p&gt;Counterarguments to &lt;a href=&quot;https://twitter.com/joeldrapper/status/1592826867027161088?cxt=HHwWgMDR3ZXm7ZosAAAA&quot;&gt;Joel Drapper’s thoughts on Rails Partials&lt;/a&gt;. Joel’s points are quoted in &lt;i&gt;italics&lt;/i&gt;.&lt;/p&gt;
&lt;h2 id=&quot;leakiness&quot;&gt;Leakiness&lt;/h2&gt;
&lt;p&gt;&lt;q&gt;[Partials are] leaky — instance variables are implicitly shared with all other views and the controller.&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;I don’t think this is &lt;em&gt;that&lt;/em&gt; bad. Controller instance variables are basically template globals, and just as general wisdom advises to “avoid globals”, we can solve this with a simple design rule: &lt;em&gt;don’t use instance variables in partials&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;view-logic&quot;&gt;View Logic&lt;/h2&gt;
&lt;p&gt;&lt;q&gt;it’s difficult to create partials that encapsulate view logic — they’re like a procedural script with no clear way to extract methods, attributes and calculations.&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;Borrowing from the design of Svelte and &lt;a href=&quot;https://github.com/domchristie/domchristie.co.uk/tree/3cb385569f38c5ef2d11a67d0c419835839f0090/src/components&quot;&gt;Astro components&lt;/a&gt;, I like to run a bit of embedded Ruby setup at the top, then include the markup below. It is procedural, but if the setup becomes unwieldy, then it might be time to refactor (perhaps with view models/presenters). Most my setup code is destructuring locals and setting defaults, so Rails 7.1’s strict locals (see &lt;a href=&quot;#interface&quot;&gt;Interface&lt;/a&gt; below), combined with &lt;a href=&quot;https://domchristie.co.uk/posts/destructuring-js-ruby/&quot;&gt;Ruby’s new destructuring capabilities&lt;/a&gt;, will result in some pretty tidy code.&lt;/p&gt;
&lt;h2 id=&quot;inheritance--composition&quot;&gt;Inheritance &amp;#x26; Composition&lt;/h2&gt;
&lt;p&gt;&lt;q&gt;there’s no inheritance or ability to share concerns between different partials without hitting the leaky problem again.&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;&lt;q&gt;It’s one-partial-per-file, so you can’t break a partial down into related parts and use composition.&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;Partials can render other partials, providing both inheritence and composition. For example a domain partial, &lt;code&gt;_post.html.erb&lt;/code&gt; could render a low-level &lt;code&gt;_card.html.erb&lt;/code&gt; (inheritence), and include &lt;code&gt;_date.html.erb&lt;/code&gt; (composition).&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# _card.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&amp;#x3C;%= image_url %&gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&amp;#x3C;%= heading %&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# _date.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;datetime&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&amp;#x3C;%= date.to_fs(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:iso8601&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;) %&gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= date.to_fs(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:short&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# _post.html.erb %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= render &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;heading:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post.title, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;image_url:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post.image_url &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= render &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;date:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post.published_at %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  by &amp;#x3C;%= post.author %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;interface&quot;&gt;Interface&lt;/h2&gt;
&lt;p&gt;&lt;q&gt;Partials never had a way to define an explicit interface or default “assigns” — I think this might be possible with “strict locals” now, but magic comments are far from ideal and they’re &lt;strong&gt;yet another syntax to learn.&lt;/strong&gt;&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://edgeguides.rubyonrails.org/action_view_overview.html#strict-locals&quot;&gt;Rails 7.1’s strict locals&lt;/a&gt; are a pragmatic solution to this and the syntax isn’t hard to learn (see below). I’d argue that learning to adapt partials is easier than learning the principles and syntax of another view library.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;&amp;#x3C;%# locals: (message: &quot;Hello, world!&quot;) -%&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= message %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;slots&quot;&gt;Slots&lt;/h2&gt;
&lt;p&gt;&lt;q&gt;Partials don’t have slots. You can yield exactly one block into them.&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;It’s relatively straightforward to augment partials to support multiple slots by passing in an object to a partial’s &lt;code&gt;yield&lt;/code&gt;. This is effectively what &lt;a href=&quot;https://github.com/bullet-train-co/nice_partials&quot;&gt;nice_partials&lt;/a&gt; does, but it’s also possible to roll your own solution in around 30 lines-of-code. (I’ll share this snippet at some point.)&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Your mileage may vary, but for the apps I’ve worked on, partials feel like a good fit. They may have been misused in the past, but with a few conventions and enhancements, they can be a really powerful tool for composing templates. I do wish they were a little faster, and were easier to test, but perhaps I just need to dig a bit deeper into caching and view testing.&lt;/p&gt;</description><pubDate>Thu, 17 Nov 2022 11:41:29 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-11-17/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-11-17/</guid><description>&lt;p&gt;Run migrations after a deploy to Heroku. In &lt;code&gt;Procfile&lt;/code&gt;, add a &lt;code&gt;release&lt;/code&gt; command:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;web: bin/rails server -p $PORT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;release: rails db:migrate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Learnt via Justin Searls’s &lt;a href=&quot;https://www.youtube.com/watch?v=XvQxfMBp50k&quot;&gt;The Selfish Programmer talk&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 17 Nov 2022 10:52:53 GMT</pubDate></item><item><title>Continuous Delivery</title><link>https://domchristie.co.uk/posts/continuous-delivery/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/continuous-delivery/</guid><description>&lt;p&gt;&lt;a href=&quot;https://m--c.com&quot;&gt;Mike Coutermarsh&lt;/a&gt;’s talk at &lt;a href=&quot;https://railssaas.com/&quot;&gt;RailsSaaS&lt;/a&gt; has had an immediate impact on how I think about what can be deployed to production. Releasing small code changes has always been an approach I’ve followed, but I’ve only applied this to small refactors, upgrades, or bug fixes, rather than large features.&lt;/p&gt;
&lt;p&gt;Mike’s approach recommends breaking down a feature into smaller, deployable elements, that can be hidden behind a feature flag (using something like &lt;a href=&quot;https://www.flippercloud.io/&quot;&gt;Flipper&lt;/a&gt;). One example was to deploy the initial blank screen as soon as possible. When it comes to launching the feature, it’s a simple case of flipping the feature flag switch.&lt;/p&gt;
&lt;p&gt;I’m curious to see how this will work in my practice. Often it’s hard to know how to architect a feature until it’s written in full, particularly in an established codebase where a refactor might be necessary. Tom MacWright puts it well:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;okay hear me out: i think the best way to do huge refactors is to try doing them all in one, gigantic pull request / chunk, which inevitably fails and needs to be split into smaller ones. if you start with smaller ones, you won&apos;t understand the general shape until much later.&lt;/p&gt;
  &lt;cite&gt;&lt;a href=&quot;https://twitter.com/tmcw/status/1585371685133619201&quot;&gt;Tom MacWright on Twitter&lt;/a&gt;
&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;So I think it probably depends on the confidence in your small units of work, and how much of the existing codebase your new code will touch. If you feel like you’re heading down a rabbit hole, then it might be worth exploring that to inform your approach.&lt;/p&gt;</description><pubDate>Thu, 27 Oct 2022 10:33:34 GMT</pubDate></item><item><title>The Same Thing in Multiple Contexts</title><link>https://domchristie.co.uk/posts/the-same-thing-in-multiple-contexts/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-same-thing-in-multiple-contexts/</guid><description>&lt;blockquote&gt;
  &lt;p&gt;The more contexts in which something is learned, the more the learner creates abstract models, and the less they rely on any particular example. Learners become better at applying their knowledge to a situation they&apos;ve never seen before, which is the essence of creativity.&lt;/p&gt;
  &lt;cite&gt;David Epstein in Range: Why Generalists Triumph in a Specialized World, p.77&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Thu, 27 Oct 2022 10:04:50 GMT</pubDate></item><item><title>RailsInspire</title><link>https://domchristie.co.uk/posts/railsinspire/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/railsinspire/</guid><description>&lt;p&gt;&lt;a href=&quot;https://railsinspire.com/&quot;&gt;RailsInspire&lt;/a&gt;: a directory of patterns for Ruby on Rails apps. I particularly like the interface. It simply highlights the files needed to implement the pattern, including explanatory annotations. Really nice work from &lt;a href=&quot;https://jeremysmith.co/&quot;&gt;Jeremy Smith&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Mon, 24 Oct 2022 08:09:20 GMT</pubDate></item><item><title>Objections</title><link>https://domchristie.co.uk/posts/objections/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/objections/</guid><description>&lt;blockquote&gt;&lt;p&gt;Nothing will ever be attempted if all possible objections must be first overcome.&lt;/p&gt;&lt;cite&gt;Samuel Johnson&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Sat, 01 Oct 2022 16:48:06 GMT</pubDate></item><item><title>Process</title><link>https://domchristie.co.uk/posts/process/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/process/</guid><description>&lt;blockquote&gt;&lt;p&gt;Inspiration is for amateurs. The rest of us just show up and get to work. If you wait around for the clouds to part and a bolt of lightning to strike you in the brain, you are not going to make an awful lot of work. All the best ideas come out of the process; they come out of the work itself.&lt;/p&gt;&lt;cite&gt;Chuck Close&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Found via Kaushik Panchal on &lt;a href=&quot;https://www.designandculture.net/blog/3mj8mdhux1f2bqf147g3fl4mvnxg7h-b978d&quot;&gt;Design and Culture: Progress not perfection&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 01 Oct 2022 13:10:51 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-09-30/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-09-30/</guid><description>&lt;p&gt;First, an interesting &lt;a href=&quot;https://discuss.hotwired.dev/t/rails-turbo-frame-flash-and-tooltips/3788/2&quot;&gt;idea from Pascal Laliberté to combine Turbo Frames Turbo Streams&lt;/a&gt;. Useful if you want update an area outside the Turbo Frame when the frame re-renders.&lt;/p&gt;
&lt;p&gt;For example, let’s say your Turbo Frame has a form, and after submission, you want to display a notice somewhere else, the response template might look something like:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;%= turbo_frame_tag &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:like&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= render &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;form&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &amp;#x3C;%= turbo_stream.update &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:notices&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, notice %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;&amp;#x3C;% &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; %&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;Second, Rails’ &lt;a href=&quot;https://api.rubyonrails.org/classes/Enumerable.html#method-i-compact_blank&quot;&gt;&lt;code&gt;compact_blank&lt;/code&gt;&lt;/a&gt; does what it says! Works on arrays and hashes. Via &lt;a href=&quot;https://twitter.com/_swanson/status/1574500221459087381&quot;&gt;Matt Swanson on Twitter&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Fri, 30 Sep 2022 13:22:49 GMT</pubDate></item><item><title>Early Generative Art by A. Michael Noll</title><link>https://domchristie.co.uk/posts/noll/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/noll/</guid><description>&lt;p&gt;Piet Mondrian’s “Composition with Lines” (1917) is one of my favourite artworks, and in searching for a print online, I came across the art of &lt;a href=&quot;http://noll.uscannenberg.org/&quot;&gt;Professor A. Michael Noll&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Noll pioneered generative digital art in the 1960s, and in one of his experiments he &lt;a href=&quot;http://noll.uscannenberg.org/Art%20Papers/Mondrian.pdf&quot;&gt;digitally recreated “Composition with Lines”&lt;/a&gt;. Participants were asked whether they could determine the computer-generated version from the original, and which version they preferred. Only 28% were able to correctly identify the computer generated version, and 59% actually preferred it.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/composition-with-lines.jpg&quot; alt=&quot;Noll&amp;#x27;s Computer Composition with Lines next to Mondrian&amp;#x27;s Composition with Lines&quot;&gt;&lt;figcaption&gt;Left: © A. Michael Noll 1965. Right: © Rijkmuseum Kröller-Müller&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This led me to more of Noll’s work, and I was drawn to his early experiments drawing patterns programmed with Fortran. I particularly like this note:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Pattern Seven&quot; was supposed to have been a series of randomly-placed prolate cycloids but apparently something went amiss.&lt;/p&gt;&lt;cite&gt;&lt;a href=&quot;http://noll.uscannenberg.org/Art%20Papers/BTL%201962%20Memo.pdf&quot;&gt;Patterns by 7090&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src=&quot;/noll-pattern-seven.jpg&quot; alt=&quot;A series of horizontal and vertical lines make an off-centre grid. Sinusoidal-squiggles are sprinkled throughout&quot;&gt;&lt;figcaption&gt;Pattern Seven © A. Michael Noll 1962&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In his paper, Noll outlines the algorithm used to create Pattern Two (below), and I thought it’d be fun to replicate it on the web.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/noll-pattern-two.jpg&quot; alt=&quot;&quot;&gt;&lt;figcaption&gt;Pattern Two © A. Michael Noll 1962&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;… and here’s my replica:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/domchristie-pattern-two.jpg&quot; alt=&quot;&quot;&gt;&lt;figcaption&gt;Pattern Two replica captured from HTML canvas. &lt;a href=&quot;/patterns.html&quot;&gt;Source&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Thankfully I didn’t have to set up and CRT or a 35mm film camera (although perhaps that would’ve been fun?!) but there was a bit of wrangling to get it looking right. Perhaps I could run an experiment to see which people prefer?&lt;/p&gt;</description><pubDate>Thu, 22 Sep 2022 14:38:42 GMT</pubDate></item><item><title>BADBADNOTGOOD - Weight Off</title><link>https://domchristie.co.uk/posts/badbadnotgood-weight-off/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/badbadnotgood-weight-off/</guid><description>&lt;iframe style=&quot;--width: 560; --height: 315&quot; src=&quot;https://www.youtube-nocookie.com/embed/x5teRSBC0R8&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Thu, 15 Sep 2022 09:42:42 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-09-14/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-09-14/</guid><description>&lt;p&gt;CSS media feature: &lt;code&gt;@media (hover|any-hover: hover) {…}&lt;/code&gt;, useful for preventing annoying ghost hover states on touch devices. Via &lt;a href=&quot;https://twitter.com/samselikoff/status/1570089403468464129&quot;&gt;Sam Selikoff on Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nabeo/rbenv-gem-migrate&quot;&gt;rbenv-gem-migrate&lt;/a&gt; to migrate gems to a new version&lt;/p&gt;</description><pubDate>Wed, 14 Sep 2022 18:07:33 GMT</pubDate></item><item><title>Die With Me by Dries Depoorter</title><link>https://domchristie.co.uk/posts/die-with-me/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/die-with-me/</guid><description>&lt;p&gt;I love this kind of art. &lt;a href=&quot;https://driesdepoorter.be/diewithme/&quot;&gt;Die With Me&lt;/a&gt; by Dries Depoorter: &lt;q&gt;The chat app you can only use when you have less than 5% battery&lt;/q&gt;&lt;/p&gt;</description><pubDate>Tue, 13 Sep 2022 17:26:09 GMT</pubDate></item><item><title>BART</title><link>https://domchristie.co.uk/posts/bart/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/bart/</guid><description>&lt;figure&gt;&lt;img alt=&quot;A window on a BART train looking out on to a foggy landscape with trees&quot; src=&quot;https://live.staticflickr.com/65535/52356281378_7d174e45de_k.jpg&quot;&gt;&lt;figcaption&gt;BART, April 2022&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Tue, 13 Sep 2022 17:17:31 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-09-13/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-09-13/</guid><description>&lt;p&gt;Didn’t strictly learn this today, but needed to note it down so I remember. &lt;code&gt;scroll-padding&lt;/code&gt; applies to scroll containers; &lt;code&gt;scroll-margin&lt;/code&gt; applies to scroll items.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://softwareas.com/audiovideo-tag-dont-forget-to-load-before-you-play/&quot;&gt;Calling &lt;code&gt;load()&lt;/code&gt; before &lt;code&gt;play()&lt;/code&gt;&lt;/a&gt; on a media element is recommended when switching the &lt;code&gt;src&lt;/code&gt;. Hopefully this fixes the occasional &lt;code&gt;AbortError&lt;/code&gt;s I’ve been seeing on iOS.&lt;/p&gt;</description><pubDate>Tue, 13 Sep 2022 14:52:58 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-09-12/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-09-12/</guid><description>&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:placeholder-shown&quot;&gt;&lt;code&gt;:placeholder-shown&lt;/code&gt;&lt;/a&gt; CSS pseudo selector: could be really useful for conditionally displaying adjacent/sibling depending on whether the input has a value.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Customise how Ruby destructures an object by defining a &lt;a href=&quot;https://ruby-doc.org/core-3.1.2/doc/syntax/pattern_matching_rdoc.html#label-Matching+non-primitive+objects-3A+deconstruct+and+deconstruct_keys&quot;&gt;&lt;code&gt;deconstruct_keys&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;</description><pubDate>Mon, 12 Sep 2022 18:59:59 GMT</pubDate></item><item><title>Destructuring: JavaScript vs. Ruby</title><link>https://domchristie.co.uk/posts/destructuring-js-ruby/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/destructuring-js-ruby/</guid><description>&lt;p&gt;Combining Ruby 2.7’s pattern matching, and Ruby 3’s rightward assignment, we can achieve something similar to JavaScript’s destructuring assignment. Jared White covers this well in &lt;a href=&quot;https://www.fullstackruby.dev/ruby-3-fundamentals/2021/01/06/everything-you-need-to-know-about-destructuring-in-ruby-3/&quot;&gt;Everything You Need to Know About Destructuring in Ruby 3&lt;/a&gt;. For those familiar the JavaScript syntax, here are some comparisons for destructuring objects/hashes:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// JavaScript&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { a: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// a === 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# Ruby&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} =&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# a == 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Rightward assignment might take some getting used to: variables on the right get assigned values from the left.)&lt;/p&gt;
&lt;h2 id=&quot;variable-naming&quot;&gt;Variable Naming&lt;/h2&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// JavaScript&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { a: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// b === 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# Ruby&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} =&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; b} &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# b == 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;rest&quot;&gt;…rest&lt;/h2&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// JavaScript&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;rest&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { a: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, b: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// a === 1, rest === { b: 2 }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# Ruby&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} =&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;rest} &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# a == 1, rest == {b: 2}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;default-values&quot;&gt;Default Values&lt;/h2&gt;
&lt;p&gt;There’s currently no Ruby syntax equivalent to that of JavaScript for setting default values whilst destructuring. &lt;code&gt;merge&lt;/code&gt; is probably the best choice here. Let’s say we wanted defaults of &lt;code&gt;a = 42&lt;/code&gt; and &lt;code&gt;b = 2&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// JavaScript&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { a: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// a === 1, b === 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# Ruby&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}.merge({&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}) =&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# a == 1, b == 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;nil-values&quot;&gt;Nil Values&lt;/h2&gt;
&lt;p&gt;In JavaScript, attempting to destructure a key that does not exist on the source, results in a variable being &lt;code&gt;undefined&lt;/code&gt;. In Ruby, pattern matching expects a pattern to match (obviously), so if a key does not exist on the source it will throw &lt;code&gt;NoMatchingPatternError&lt;/code&gt;. However, we can mimic JavaScript’s relaxed behaviour by defining a &lt;a href=&quot;https://ruby-doc.org/core-3.1.2/doc/syntax/pattern_matching_rdoc.html#label-Matching+non-primitive+objects-3A+deconstruct+and+deconstruct_keys&quot;&gt;&lt;code&gt;deconstruct_keys&lt;/code&gt;&lt;/a&gt; method on our source, and merge any undefined keys.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// JavaScript&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; { a: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// a === 1, b === undefined&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Props&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Hash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;deconstruct_keys&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(keys)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(keys).to_h { |k| [k, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;] }.merge(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Props&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;[{&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}] =&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;a:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;b:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# a == 1, b == nil&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;http://elliot.cm/&quot;&gt;Elliot Crosby-McCullough&lt;/a&gt; on the &lt;a href=&quot;https://discord.com/invite/stimulus-reflex&quot;&gt;StimulusReflex Discord&lt;/a&gt; for this idea and code snippet.&lt;/p&gt;</description><pubDate>Mon, 12 Sep 2022 18:09:29 GMT</pubDate></item><item><title>How To with John Wilson</title><link>https://domchristie.co.uk/posts/how-to-with-john-wilson/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/how-to-with-john-wilson/</guid><description>&lt;p&gt;This looks like just my kind of thing.&lt;/p&gt;
&lt;iframe style=&quot;--width: 560; --height: 315&quot; src=&quot;https://www.youtube-nocookie.com/embed/w7aSybHRa6s?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Mon, 12 Sep 2022 09:24:59 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-09-11/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-09-11/</guid><description>&lt;p&gt;Ruby’s &lt;code&gt;|=&lt;/code&gt; operator: appends values to the array that don’t already exist.&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;a &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;a &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;|=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# a == [1, 2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;a &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;|=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# a == [1, 2]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;via &lt;a href=&quot;https://twitter.com/faqndoE97/status/1564612351281831945&quot;&gt;Facundo Espinosa on Twitter&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;code&gt;irb&lt;/code&gt; accepts an &lt;code&gt;-r&lt;/code&gt; option to automatically require gems:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;irb -r down&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;tempfile &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Down&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.download(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;http://example.com&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;# look! no require!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;via &lt;a href=&quot;https://twitter.com/collin_jilbert/status/1568793560861888514&quot;&gt;Collin Jilbert on Twitter&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods/WhereChain.html#method-i-missing&quot;&gt;Ruby on Rails’ &lt;code&gt;missing&lt;/code&gt;&lt;/a&gt; fetches records that do not have an associated record. For example A &lt;code&gt;Post&lt;/code&gt; that does not have any associated &lt;code&gt;Comment&lt;/code&gt;s:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;Post&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.where.missing(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;:comments&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Sun, 11 Sep 2022 19:02:51 GMT</pubDate></item><item><title>Today I Learned</title><link>https://domchristie.co.uk/posts/til-2022-09-09/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/til-2022-09-09/</guid><description>&lt;p&gt;Ruby’s &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-tally&quot;&gt;Enumerable#tally&lt;/a&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;].tally  &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;#=&gt; {&quot;a&quot;=&gt;1, &quot;b&quot;=&gt;2, &quot;c&quot;=&gt;1}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://guides.rubyonrails.org/command_line.html#bin-rails-runner&quot;&gt;&lt;code&gt;rails runner&lt;/code&gt;&lt;/a&gt; runs Ruby code (including Ruby files) in a Rails context from the command line:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;bin/rails runner lib/code_to_be_run.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Fri, 09 Sep 2022 20:28:31 GMT</pubDate></item><item><title>TailwindInk</title><link>https://domchristie.co.uk/posts/tailwind-ink/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tailwind-ink/</guid><description>&lt;p&gt;&lt;a href=&quot;https://tailwind.ink/&quot;&gt;TailwindInk&lt;/a&gt; is the nicest tool I’ve seen for generating colour palettes for the web. The swatches are evenly balanced, various contrast ratios are displayed, and the code is easily imported into Tailwind.&lt;/p&gt;</description><pubDate>Fri, 09 Sep 2022 11:34:13 GMT</pubDate></item><item><title>Rails Redesign</title><link>https://domchristie.co.uk/posts/rails-redesign/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/rails-redesign/</guid><description>&lt;p&gt;I can’t help but feel a little disappointed by the new &lt;a href=&quot;https://rubyonrails.org/&quot;&gt;Ruby on Rails site&lt;/a&gt; launched last year. It’s undoubtedly more up-to-date, but gone is the emphasis on fun and friendliness, and in its place, a focus on business and making money.&lt;/p&gt;
&lt;p&gt;Aside from the removal of the happy handdrawn cartoons, the contrast in copy is revealing. Where previously it opened with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Imagine&lt;/em&gt; what you could build&lt;/strong&gt; …&lt;br&gt;
Learning to build a modern web application is daunting. Ruby on Rails makes it much &lt;strong&gt;easier and more fun&lt;/strong&gt;. It includes everything you need to &lt;strong&gt;build fantastic applications&lt;/strong&gt;, and you can learn it with the support of our large, &lt;strong&gt;friendly community&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Emphasis my own.) It now reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Compress the complexity of modern web apps.&lt;/strong&gt;&lt;br&gt;
Learn just what you need to get started, then keep leveling up as you go. Ruby on Rails scales from HELLO WORLD to &lt;strong&gt;IPO&lt;/strong&gt; …&lt;/p&gt;
&lt;p&gt;Over the past two decades, Rails has taken countless companies to millions of users and &lt;strong&gt;billions in market valuations&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Happiness&lt;/strong&gt; does get a mention, but sadly it’s the last thing mentioned, and feels lost amongst the business spiel.&lt;/p&gt;
&lt;p&gt;For Rails apps themselves, the start up graphic has also been removed and I will certainly miss this happy scene 🥲&lt;/p&gt;
&lt;figure&gt;&lt;img width=&quot;896&quot; height=&quot;612&quot; src=&quot;/rails-startup.jpg&quot; alt=&quot;The old startup image for Ruby on Rails apps picturing a cartoon globe with a diverse crowd of happy people&quot;&gt;&lt;/figure&gt;</description><pubDate>Fri, 09 Sep 2022 11:34:05 GMT</pubDate></item><item><title>Severance</title><link>https://domchristie.co.uk/posts/severance/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/severance/</guid><description>&lt;p&gt;&lt;span style=&quot;font-family: Helvetica Neue&quot;&gt;&lt;a href=&quot;https://tv.apple.com/us/show/severance/umc.cmc.1srk2goyh2q2zdxcx605w8vtx&quot;&gt;Severance&lt;/a&gt;&lt;/span&gt; might be the best thing I’ve seen on TV: dark, original, funny, and gripping with some satisfying twists. Great cast, intriguing characters, and an eery soundtrack too. I absolutely loved it.&lt;/p&gt;</description><pubDate>Sun, 04 Sep 2022 15:17:49 GMT</pubDate></item><item><title>Haitus Kaiyote</title><link>https://domchristie.co.uk/posts/haitus-kaiyote/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/haitus-kaiyote/</guid><description>&lt;p&gt;Haitus Kaiyote played a great set supporting Flying Lotus at the Hollywood Bowl the other day. They opened with Red Room, and I was hooked.&lt;/p&gt;
&lt;iframe style=&quot;--width: 560; --height: 315&quot; src=&quot;https://www.youtube-nocookie.com/embed/p46Tm9-7i7E?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 02 Sep 2022 00:00:00 GMT</pubDate></item><item><title>Bleep!</title><link>https://domchristie.co.uk/posts/bleep/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/bleep/</guid><description>&lt;p&gt;Interesting to hear the origin of bleeping or editing-out offensive words on the radio, and how it’s done technically; &lt;a href=&quot;https://99percentinvisible.org/episode/bleep/&quot;&gt;Bleep!&lt;/a&gt; from 99% Invisible also discusses the ethics of censorship and the subtle differences between bleeping-out, editing-out, or leaving in.&lt;/p&gt;</description><pubDate>Thu, 25 Aug 2022 12:32:28 GMT</pubDate></item><item><title>Add to Safari Reading List from Firefox</title><link>https://domchristie.co.uk/posts/add-to-reading-list/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/add-to-reading-list/</guid><description>&lt;p&gt;Useful if you typically use Firefox but wish to save articles to read in Safari’s Reading List (on an iPad).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the macOS Automator app&lt;/li&gt;
&lt;li&gt;File menu, New, and choose Quick Action (the cog)&lt;/li&gt;
&lt;li&gt;Update the following the dropdown menus:
&lt;ul&gt;
&lt;li&gt;Workflow receives no input&lt;/li&gt;
&lt;li&gt;in Firefox&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click and drag the Run AppleScript action into the workflow area&lt;/li&gt;
&lt;li&gt;Replace the script with the following:
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;-- send cmd+l and cmd+c keystrokes to FF to highlight and copy the URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;tell&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;System Events&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;keystroke&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;l&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; using {command down}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;keystroke&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; using {command down}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;key code&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;53&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;--escape&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;end tell&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;tell&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Safari&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; add reading &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;the&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; clipboard)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Save as Add to Reading List&lt;/li&gt;
&lt;li&gt;Open Firefox and find an article&lt;/li&gt;
&lt;li&gt;Firefox menu, Services, Add to Reading List&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Adapted from: &lt;a href=&quot;https://www.alfredforum.com/topic/4778-add-firefox-url-to-reading-list/&quot;&gt;Add Firefox URL to Reading List&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sun, 21 Aug 2022 00:00:00 GMT</pubDate></item><item><title>Seven</title><link>https://domchristie.co.uk/posts/seven/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/seven/</guid><description>&lt;p&gt;I watched David Fincher’s Seven for the first time the other day. It’s got that 90s grungy look to it, but it holds up really well.&lt;/p&gt;
&lt;p&gt;This scene caught my attention in particular. The two detectives, Mills (Brad Pitt) and Somerset (Morgan Freeman), discuss how they’re going to track down a serial killer. Somerset had convinced his contact at the F.B.I to do some discreet background research, and explains this to Mills.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SOMERSET: For a long time, the F.B.I.’s been hooked into the library system, keeping accurate records.&lt;/p&gt;
&lt;p&gt;MILLS: What? Assessing fines?&lt;/p&gt;
&lt;p&gt;SOMERSET: They monitor reading habits. Not every book, but certain ones are flagged. Books about… let’s say, how to build a nuclear bomb, or maybe Mein Kampf. Whoever takes out a flagged book has their library records fed to the F.B.I. from then on.&lt;/p&gt;
&lt;p&gt;MILLS: You got to be kidding.&lt;/p&gt;
&lt;p&gt;SOMERSET: Flagged books cover every topic the Bureau deems questionable… communism to violent crime.&lt;/p&gt;
&lt;p&gt;MILLS: How is this legal?&lt;/p&gt;
&lt;p&gt;SOMERSET: Legal… illegal. These terms don’t apply.
I don’t applaud it.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;https://www.dailyscript.com/scripts/seven_production.html&quot;&gt;The Daily Script&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mills’ disbelief—on ethical grounds—that the F.B.I. tracks the odd library book, really highlights how attitudes to privacy have changed in the past 25 years.&lt;/p&gt;</description><pubDate>Thu, 02 Jun 2022 00:00:00 GMT</pubDate></item><item><title>Glider</title><link>https://domchristie.co.uk/posts/glider/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/glider/</guid><description>&lt;figure&gt;&lt;img src=&quot;/glider.png&quot; width=&quot;896&quot; height=&quot;613&quot; alt=&quot;Black and white screenshot of the Glider video game. A paper aeroplane hovers above a central air vent. In the room there is an old Apple Macintosh computer and an alarm clock sat on a table.&quot;&gt;&lt;/figure&gt;
&lt;p&gt;Not sure what triggered this, but I had a mad urge to play this game the other day. Alongside Prince of Persia, Glider 4.0 was one of my favourite games growing up.&lt;/p&gt;
&lt;p&gt;You play as a paper aeroplane kept afloat by air vents, with the aim of navigating from one room to the next, avoiding other objects. Along the way to the top of the house, you’ll have to dodge balloons, bouncing balls, jumping goldfish, and other paper aeroplanes, whilst being accompanied by a funky bass riff as you enter each room.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=s8_ypI_C7nM&quot;&gt;This playthrough&lt;/a&gt; makes it look much easier than I remember. Thankfully someone has made &lt;a href=&quot;https://www.kodogo.tech/glider/&quot;&gt;a port of Glider 4.0 for the web&lt;/a&gt;, and 30 years on it’s … just as hard as I remember!&lt;/p&gt;</description><pubDate>Fri, 18 Mar 2022 00:00:00 GMT</pubDate></item><item><title>Geisel Library</title><link>https://domchristie.co.uk/posts/geisel-library/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/geisel-library/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/50489946771/in/photostream/&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;606&quot; src=&quot;https://live.staticflickr.com/65535/50489946771_e030c2cfd1_k.jpg&quot; alt=&quot;Side-on perspective of The Geisel Library, San Diego&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Geisel Library. La Jolla, San Diego 2020&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Took a trip to San Diego at the weekend, and managed to fit in a visit to the Geisel Library on the University of California campus. It’s a breathtaking building. I wonder how on earth &lt;a href=&quot;https://en.wikipedia.org/wiki/William_Pereira&quot;&gt;William Pereira&lt;/a&gt; came up with such an incredible concept.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/50490094262/in/dateposted/&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;606&quot; src=&quot;https://live.staticflickr.com/65535/50490094262_df898bc7e2_k.jpg&quot; alt=&quot;Corner perspective of the Geisel Library, San Diego&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;So. Brutal.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/50489947331/in/photostream/&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;606&quot; src=&quot;https://live.staticflickr.com/65535/50489947331_a5f1ddff0a_k.jpg&quot; alt=&quot;Entrance to The Geisel Library, San Diego&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;More symmetry&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Thu, 15 Oct 2020 00:00:00 GMT</pubDate></item><item><title>Mustang</title><link>https://domchristie.co.uk/posts/mustang/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/mustang/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/50187927333/in/dateposted/&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;612&quot; src=&quot;https://live.staticflickr.com/65535/50187927333_b679dba6aa_k.jpg&quot; alt=&quot;Hood of a vintage red Ford Mustang&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Los Feliz, Los Angeles 2020&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The shot counter on my Lomo LC-A had malfunctioned, and whilst I could feel the winder getting tight, I wasn’t sure how many frames I had left. This was the lucky last shot!&lt;/p&gt;</description><pubDate>Tue, 04 Aug 2020 00:00:00 GMT</pubDate></item><item><title>Found Poetry: Deeper than that</title><link>https://domchristie.co.uk/posts/found-poetry-deeper-than-that/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/found-poetry-deeper-than-that/</guid><description>&lt;p&gt;&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/deeper_than_that.jpg&quot; alt=&quot;Deeper than that. Brexit is now giving birth to a new realigment. Brexit identities.  Relatives marry / Remainers. What could this mean?&quot;&gt;&lt;/p&gt;</description><pubDate>Wed, 22 May 2019 00:00:00 GMT</pubDate></item><item><title>Photo Me</title><link>https://domchristie.co.uk/posts/photo-me/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/photo-me/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/46633591944/in/dateposted/&quot; title=&quot;photo me&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;645&quot; src=&quot;https://live.staticflickr.com/7922/46633591944_ce78232cc5_k.jpg&quot; alt=&quot;Someone sitting in a photo booth having their passport photo taken&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Euston Station, London 2018&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Tue, 12 Mar 2019 00:00:00 GMT</pubDate></item><item><title>Tunng—Sleepwalking</title><link>https://domchristie.co.uk/posts/tunng-sleepwalking/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tunng-sleepwalking/</guid><description>&lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allow=&quot;autoplay&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/473865843&amp;#x26;color=%23ff5500&amp;#x26;auto_play=false&amp;#x26;hide_related=true&amp;#x26;show_comments=false&amp;#x26;show_user=true&amp;#x26;show_reposts=false&amp;#x26;show_teaser=false&quot;&gt;&lt;/iframe&gt;
&lt;blockquote&gt;&lt;p&gt;This is a song about how we create the world and the world creates us in turn.&lt;/p&gt;
&lt;p&gt;Our brains construct an experience of the world around us, filtered through our own personal expectations and subconscious desires and beliefs. To a certain extent, who we think we are is an illusion and everyone who knows us, including ourselves, is experiencing someone quite different. Perhaps our subconscious world of dreams and sleepwalking is closer to the real us than our waking imaginations!&lt;/p&gt;
&lt;p&gt;This song is about trying to navigate our experience of the world, trying to figure out what&apos;s real and what&apos;s not, and making the best of what comes our way.&lt;/p&gt;
&lt;cite&gt;Tunng&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Tue, 04 Sep 2018 07:44:36 GMT</pubDate></item><item><title>The Importance of Beauty</title><link>https://domchristie.co.uk/posts/the-importance-of-beauty/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-importance-of-beauty/</guid><description>&lt;blockquote&gt;&lt;p&gt;Beauty is essential. It is never a trade-off. Make the most of beauty and never sacrifice it at the altar of expediency. It is too high a price.&lt;/p&gt;
&lt;p&gt;Add nothing ugly. Do not accept any existing ugliness as fixed. Remove and change it if possible, otherwise modify or screen it.&lt;/p&gt;
&lt;cite&gt;Monty Don &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; Down to Earth, p.32&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Sun, 19 Aug 2018 09:27:52 GMT</pubDate></item><item><title>Algarve 2017</title><link>https://domchristie.co.uk/posts/algarve-2017/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/algarve-2017/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37328741036/in/photostream/&quot; title=&quot;R0000620.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4470/37328741036_35b565586a.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Faro Train Station&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37376108451/in/photostream/&quot; title=&quot;R0000676.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4419/37376108451_d5788d55e7.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Tavira Sunset&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37376115381/in/photostream/&quot; title=&quot;R0000681.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4511/37376115381_c656c138c2.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Tavira Tiles&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37376118411/in/photostream/&quot; title=&quot;R0000686.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4416/37376118411_bcbd85bbf6.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Helen taking pictures of Tavira tiles&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/36667723294/in/photostream/&quot; title=&quot;R0000664.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4460/36667723294_b0005808d8.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Cabanas de Tavira&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/36706348633/in/photostream/&quot; title=&quot;R0000629.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4424/36706348633_6846c3d8a8.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Cabanas de Tavira&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37328763406/in/photostream/&quot; title=&quot;R0000691.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4418/37328763406_b0949d55de.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Praia Verde Modernist Village&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37328768576/in/dateposted/&quot; title=&quot;R0000692.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4460/37328768576_f9a1abf801.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Apartment in Praia Verde&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37376130371/in/photostream/&quot; title=&quot;R0000700.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4331/37376130371_253c180567.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;View from our room at the Praia Verde Boutique Hotel&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/37119710960/in/photostream/&quot; title=&quot;R0000705.jpg&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4459/37119710960_3f743a018d.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Fri, 24 Nov 2017 11:12:02 GMT</pubDate></item><item><title>Starting Small</title><link>https://domchristie.co.uk/posts/starting-small/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/starting-small/</guid><description>&lt;p&gt;Another quotation from E.F. Schumacher, this time taken from a BBC Radio 4 programme &lt;a href=&quot;http://www.bbc.co.uk/programmes/b079njxm&quot;&gt;Is Small the Next Big?&lt;/a&gt; His book, Small is Beautiful (Economics as if People Mattered), is jam-packed full of interesting ideas, and highly recommended.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;It’s quite astonishing how many people are asking, “what can I do to save the world?—I am so small!” … Everything new starts very, very small, normally in a very dark place.&lt;/p&gt;&lt;cite&gt;E.F. Schumacher &lt;span class=&quot;byline lower&quot;&gt;from&lt;/span&gt; &lt;a href=&quot;http://www.bbc.co.uk/programmes/b079njxm&quot;&gt;Is Small the Next Big?&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Thu, 02 Feb 2017 09:46:04 GMT</pubDate></item><item><title>Wisdom in Smallness</title><link>https://domchristie.co.uk/posts/wisdom-in-smallness/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/wisdom-in-smallness/</guid><description>&lt;blockquote&gt;&lt;p&gt;Small-scale operations, no matter how numerous, are always less likely to be harmful to the natural environment than large-scale ones, simply because their force is small in relation to the recuperative forces of nature. There is wisdom in smallness if only on the account of the smallness and patchiness of human knowledge, which relies on experiment far more than understanding. The greatest danger invariably arises from the ruthless application, on a vast scale, of partial knowledge such as we are currently witnessing in the application of nuclear energy, of the new chemistry in agriculture, of transportation technology, and countless other things.&lt;/p&gt;
&lt;cite&gt;E.F. Schumacher &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; Small is Beautiful 1974, &lt;span class=&quot;lower&quot;&gt;p.29&lt;/span&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Tue, 24 Jan 2017 07:56:18 GMT</pubDate></item><item><title>Photographs of Seats</title><link>https://domchristie.co.uk/posts/photographs-of-seats/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/photographs-of-seats/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31046553082/in/dateposted/&quot; title=&quot;2005-10_4444_lomo-lca_jessops-cs-100_04.jpg&quot;&gt;&lt;img src=&quot;https://c3.staticflickr.com/6/5711/31046553082_ee542df5a4.jpg&quot; alt=&quot;2005-10_4444_lomo-lca_jessops-cs-100_04.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Guildford Train Station, 2005&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/30382835743/in/photostream/&quot; title=&quot;2006-04_0575_lomo-lca_kodak-elite-chrome_07.jpg&quot;&gt;&lt;img src=&quot;https://c8.staticflickr.com/6/5768/30382835743_d11d03d179.jpg&quot; alt=&quot;2006-04_0575_lomo-lca_kodak-elite-chrome_07.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Connex/South Eastern, 2006&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31075711511/in/photostream/&quot; title=&quot;2007-05_1653_zorki-4k_kodak-bw400cn_32.jpg&quot;&gt;&lt;img src=&quot;https://c8.staticflickr.com/6/5349/31075711511_73326fbaa7.jpg&quot; alt=&quot;2007-05_1653_zorki-4k_kodak-bw400cn_32.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Willesden Green, 2007&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31046555362/in/photostream/&quot; title=&quot;2007-08_4100_lomo-lca_ilford-xp2_32.jpg&quot;&gt;&lt;img src=&quot;https://c3.staticflickr.com/6/5454/31046555362_57786a810a.jpg&quot; alt=&quot;2007-08_4100_lomo-lca_ilford-xp2_32.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Switzerland, 2007&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31189759555/in/photostream/&quot; title=&quot;2007-08_4224_lomo-lca_jessops-cs-100_07.jpg&quot;&gt;&lt;img src=&quot;https://c4.staticflickr.com/6/5544/31189759555_28c6ca0401.jpg&quot; alt=&quot;2007-08_4224_lomo-lca_jessops-cs-100_07.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Oban to Mull Ferry, 2007&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31189760885/in/photostream/&quot; title=&quot;2009-08_8136_voigtlander-bessa-r_fujifilm-superia-400_18.jpg&quot;&gt;&lt;img src=&quot;https://c6.staticflickr.com/6/5470/31189760885_c1a6744be2.jpg&quot; alt=&quot;2009-08_8136_voigtlander-bessa-r_fujifilm-superia-400_18.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Isle of Gigha Ferry, 2009&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31075714521/in/photostream/&quot; title=&quot;2010-10_5541_olympus-af1_kodak-gold-200_16.jpg&quot;&gt;&lt;img src=&quot;https://c2.staticflickr.com/6/5541/31075714521_64567a6c7a.jpg&quot; alt=&quot;2010-10_5541_olympus-af1_kodak-gold-200_16.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Fortress Studios London, 2010&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31075715301/in/photostream/&quot; title=&quot;2010-11_6985_lomo-lca_fujifilm-superia-400_15.jpg&quot;&gt;&lt;img src=&quot;https://c6.staticflickr.com/6/5657/31075715301_eab8d1dd11.jpg&quot; alt=&quot;2010-11_6985_lomo-lca_fujifilm-superia-400_15.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;New York Subway, 2010&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/31189766665/in/photostream/&quot; title=&quot;2016-09_0391_olympus-mju-ii_kodak-ektar-100_04.jpg&quot;&gt;&lt;img src=&quot;https://c2.staticflickr.com/6/5788/31189766665_2f90195669.jpg&quot; alt=&quot;2016-09_0391_olympus-mju-ii_kodak-ektar-100_04.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;North Finchley, 2016&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/50252368747/in/photostream/&quot; title=&quot;2018-07_9543_olympus-xa2_fujifilm-superia-200_10.jpg&quot;&gt;&lt;img src=&quot;https://live.staticflickr.com/65535/50252368747_cdda507ba1.jpg&quot; alt=&quot;2018-07_9543_olympus-xa2_fujifilm-superia-200_10.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Devon, 2018&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/50252183436/in/photostream/&quot; title=&quot;2019-10_0001_olympus-xa2_fujifilm-superia-200_21.jpg&quot;&gt;&lt;img src=&quot;https://live.staticflickr.com/65535/50252183436_62a1253a04.jpg&quot; alt=&quot;2019-10_0001_olympus-xa2_fujifilm-superia-200_21.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;London, 2019&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Wed, 23 Nov 2016 09:21:04 GMT</pubDate></item><item><title>Trainspotting</title><link>https://domchristie.co.uk/posts/trainspotting/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/trainspotting/</guid><description>&lt;p&gt;Quite a few of the places I&apos;ve lived in over the last decade have been right next to a train track.&lt;/p&gt;
&lt;p&gt;In my second year at university, my bedroom was pretty much in contact with a railway bridge. I can remember trying to churn out words on an essay as the first train went past, reminding me that I’d worked through to 6am 😫&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/29677292746/in/photostream/&quot; title=&quot;2006-05_1793_lomo-lca_fujifilm-super-g-400_33.jpg&quot;&gt;&lt;img src=&quot;https://c3.staticflickr.com/8/7484/29677292746_245204324d.jpg&quot; alt=&quot;2006-05_1793_lomo-lca_fujifilm-super-g-400_33.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Guildford, May 2006&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Above: it&apos;s not the clearest photo (as it has been exposed twice) but you can make out the corner of the house in the top right, and the wall of the bridge running along the length.&lt;/p&gt;
&lt;p&gt;My flat in Willesden Green had the Jubilee Line running above ground at the end of the garden:&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/29086240594/in/photostream/&quot; title=&quot;2006-08_5796_lomo-lca_jessops-cs-100_00.jpg&quot;&gt;&lt;img src=&quot;https://c3.staticflickr.com/9/8367/29086240594_dfc70e73ea.jpg&quot; alt=&quot;2006-08_5796_lomo-lca_jessops-cs-100_00.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Willesden Green, Jubilee Line, August 2006.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The scene above, taken 10 years ago, is remarkably similar to the situation in my current flat:&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/29603375981/in/photostream/&quot; title=&quot;R0000419.jpg&quot;&gt;&lt;img src=&quot;https://c6.staticflickr.com/9/8321/29603375981_a79e3d0976.jpg&quot; alt=&quot;R0000419.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;East Finchley, Northern Line, August 2016.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Anyway a few weeks back, just as I was heading to bed, a train pulled up at the end of the garden and stopped. I could just make out the voice of the driver over the tannoy. Perhaps I was the only one listening—the train seemed pretty empty.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/29649079726/in/photostream/&quot; title=&quot;R0000414.jpg&quot;&gt;&lt;img src=&quot;https://c7.staticflickr.com/9/8389/29649079726_86e83ea0f7.jpg&quot; alt=&quot;R0000414.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/29684649615/in/dateposted/&quot; title=&quot;R0000415.jpg&quot;&gt;&lt;img src=&quot;https://c8.staticflickr.com/9/8415/29684649615_25512e5a35.jpg&quot; alt=&quot;R0000415.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/29684635895/in/photostream/&quot; title=&quot;R0000410.jpg&quot;&gt;&lt;img src=&quot;https://c8.staticflickr.com/9/8355/29684635895_90d7f38a78.jpg&quot; alt=&quot;R0000410.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Wed, 21 Sep 2016 07:53:14 GMT</pubDate></item><item><title>Conway’s Game of Life with Redux + Canvas</title><link>https://domchristie.co.uk/posts/conway-s-game-of-life-with-redux-canvas/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/conway-s-game-of-life-with-redux-canvas/</guid><description>&lt;p&gt;&lt;a href=&quot;http://jsbin.com/cijefu&quot;&gt;&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/conways-game-of-life-redux.png&quot; alt=&quot;Animation of Conway’s Game of Life&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the past few weeks I’ve been doing a fair bit of work with &lt;a href=&quot;http://redux.js.org&quot;&gt;Redux&lt;/a&gt;, a library which helps manage data and state in JavaScript applications. There’s an emphasis on functional programming and immutable data, which takes a little getting used to, but it does feel like a suitable approach—particularly for implementing Conway’s Game of Life…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;each generation is a pure function of the preceding one&lt;/p&gt;
&lt;cite&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules&quot;&gt;Conway’s Game of Life on Wikipedia&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;p&gt;This fits nicely with Redux’s concept of “reducers”, which take in the current state and an “action”, and return a new state.&lt;/p&gt;
&lt;p&gt;The app state is just the grid: an array of arrays containing cell values (1s and 0s). There is just a single action, a &lt;code&gt;&apos;TICK&apos;&lt;/code&gt;, and when a &lt;code&gt;&apos;TICK&apos;&lt;/code&gt; is dispatched, the &lt;code&gt;grid&lt;/code&gt; reducer generates a new grid based on the current grid:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; state &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;undefined&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;randomGrid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (action.type) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;TICK&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;nextGrid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(state)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;nextGrid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; grid.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;nextGrid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;currentRow&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; newRow &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; currentRow.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;nextValue&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(x, y, value, grid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    nextGrid.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(newRow)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; nextGrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The grid values for the next tick are computed based on the neighbouring values (as per &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules&quot;&gt;the rules&lt;/a&gt;):&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;nextValue&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; neighbours &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;neighboursOf&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(x, y, grid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; livingNeighbours &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; neighbours.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;!!&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }).&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;length&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;willLive&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(value, livingNeighbours)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;willLive&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;livingNeighbours&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; livingNeighbours &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; livingNeighbours &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; livingNeighbours &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;neighboursOf&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;/*x,y*/&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  ].&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;coords&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;valueAt&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(x &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; coords[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], y &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; coords[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;], grid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;valueAt&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; grid[y] &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;amp; grid[y][x] }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;render&lt;/code&gt; function redraws the state on a &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; whenever it changes, and a &lt;code&gt;&apos;TICK&apos;&lt;/code&gt; is dispatched every 100ms to generate the next state: &lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; store &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Redux.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;createStore&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(grid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;store.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;subscribe&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(render)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;setInterval&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  store.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({ type: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;TICK&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m sure this could be improved, but it feels like a pretty nice solution.&lt;/p&gt;
&lt;p&gt;See it in action: &lt;a href=&quot;http://jsbin.com/cijefu&quot;&gt;Conway’s Game of Life with Redux and Canvas&lt;/a&gt;, and &lt;a href=&quot;http://jsbin.com/cijefu/edit?html,css,js,output&quot;&gt;view the full source&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Hat tip to &lt;a href=&quot;https://github.com/alanrsoares&quot;&gt;Alan R. Soares&lt;/a&gt;. I had a peak at &lt;a href=&quot;https://github.com/alanrsoares/redux-game-of-life&quot;&gt;his implementation with React&lt;/a&gt; and refined my &lt;code&gt;willLive&lt;/code&gt; function a based on it.&lt;/small&gt;&lt;/p&gt;</description><pubDate>Wed, 09 Mar 2016 09:43:13 GMT</pubDate></item><item><title>February 2016 Playlist</title><link>https://domchristie.co.uk/posts/february-2016-playlist/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/february-2016-playlist/</guid><description>&lt;h2&gt;Advice to Young Girls by Inga Copeland (w/Actress)&lt;/h2&gt;
&lt;p&gt;Discovered this via &lt;a href=&quot;http://jajajamusic.com/2016/02/recommended-listening-ctm-interview-ja-ja-ja-london/&quot;&gt;CTM’s Recommended Listening feature&lt;/a&gt;.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/228385495&amp;#x26;color=fa8072&amp;#x26;auto_play=false&amp;#x26;hide_related=false&amp;#x26;show_comments=true&amp;#x26;show_user=true&amp;#x26;show_reposts=false&quot;&gt;&lt;/iframe&gt;
&lt;h2&gt;Perth by Beirut&lt;/h2&gt;
&lt;p&gt;I got a DAB radio for my birthday, so I’ve been listening to the radio a lot more. This catchy tune caught my ear. Their latest album is pretty good too.&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/rVnZBiFQQ-I?rel=0&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2&gt;Amerika by Liima&lt;/h2&gt;
&lt;p&gt;New from the Efterklang + Finnish percussionist Tatu Rönkkö.&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/RrAQHUsw8SA?rel=0&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2&gt;Zap by Vinny Villbass&lt;/h2&gt;
&lt;p&gt;Heard this at the Ja Ja Ja London Club Night. The 90s house-y synth section in the middle is madness!&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/206064000&amp;#x26;color=fa8072&amp;#x26;auto_play=false&amp;#x26;hide_related=false&amp;#x26;show_comments=true&amp;#x26;show_user=true&amp;#x26;show_reposts=false&quot;&gt;&lt;/iframe&gt;
&lt;h2&gt;Because by Smerz&lt;/h2&gt;
&lt;p&gt;Smerz headlined at the Ja Ja Ja club night and were really great live. Can’t wait to hear more stuff from them.&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/0ZiEMnPcmQQ?rel=0&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Mon, 07 Mar 2016 09:32:28 GMT</pubDate></item><item><title>Converse</title><link>https://domchristie.co.uk/posts/converse/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/converse/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/24019292190/in/dateposted/&quot; title=&quot;R0000244.jpg&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;606&quot; src=&quot;https://live.staticflickr.com/1491/24019292190_b647d82608_k.jpg&quot; alt=&quot;R0000244.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;East Finchley, London. January 2016.&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Tue, 12 Jan 2016 08:09:54 GMT</pubDate></item><item><title>Bløsh—Give It Away</title><link>https://domchristie.co.uk/posts/blosh-give-it-away/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/blosh-give-it-away/</guid><description>&lt;iframe data-width=&quot;500&quot; data-height=&quot;281&quot; src=&quot;https://www.youtube-nocookie.com/embed/gb5sVYgDc1Q?rel=0&amp;#x26;controls=0&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 08 Jan 2016 10:13:00 GMT</pubDate></item><item><title>Letterpress</title><link>https://domchristie.co.uk/posts/letterpress/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/letterpress/</guid><description>&lt;p&gt;I had an amazing time at &lt;a href=&quot;http://harringtonandsquires.co.uk&quot;&gt;Harrington &amp;#x26; Squires&lt;/a&gt;, learning about the art of letterpress printing. Chrissie and Vicky were such great hosts, and if you get a chance, I’d highly recommend their &lt;a href=&quot;http://harringtonandsquires.co.uk/pages/info-harringtonandsquires-co-uk&quot;&gt;workshops&lt;/a&gt;, or visiting their shop in Tufnell Park.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22839311179/in/dateposted/&quot; title=&quot;Above all else show the data&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/700/22839311179_a4d855f929.jpg&quot; alt=&quot;Above all else show the data&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;A finished print—Tufte’s “show the data” quotation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22837938509/in/photostream/&quot; title=&quot;Fluorescent Ink Roller&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5627/22837938509_aaaa3dbac9.jpg&quot; alt=&quot;Fluorescent Ink Roller&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Unfortunately the photo doesn’t do justice to the fluorescence of that orange!&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22838529589/in/dateposted/&quot; title=&quot;First Pass&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5682/22838529589_9c40f1fa10.jpg&quot; alt=&quot;First Pass&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22811720917/in/photostream/&quot; title=&quot;Chase in the press&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/769/22811720917_6bb08b8eb8.jpg&quot; alt=&quot;Chase in the press&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22578774233/in/photostream/&quot; title=&quot;Second Pass&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5730/22578774233_5ae0688fbf.jpg&quot; alt=&quot;Second Pass&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22837949579/in/photostream/&quot; title=&quot;Printing Presses&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5821/22837949579_587a7331ce.jpg&quot; alt=&quot;Printing Presses&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Adana 8 x 5 printing presses. Want.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/22578810523/in/photostream/&quot; title=&quot;&amp;#x22;Furniture&amp;#x22; and cases of type&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/706/22578810523_1f94b17614.jpg&quot; alt=&quot;&amp;#x22;Furniture&amp;#x22; and cases of type&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;“Furniture” and numerous cases of type.&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Sun, 22 Nov 2015 15:34:46 GMT</pubDate></item><item><title>Efterklang’s Mirador vs. ustwo’s Monument Valley</title><link>https://domchristie.co.uk/posts/efterklang-s-mirador-vs-ustwo-s-monument-valley/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/efterklang-s-mirador-vs-ustwo-s-monument-valley/</guid><description>&lt;p&gt;Some remarkable similarities between these two M.C. Escher-alikes.&lt;/p&gt;
&lt;h2&gt;Efterklang—Mirador (2008)&lt;/h2&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/2203531?color=ffffff&amp;#x26;title=0&amp;#x26;byline=0&amp;#x26;portrait=0&quot; style=&quot;--width: 500; --height: 375&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2&gt;Monument Valley (2014)&lt;/h2&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/wC1jHHF_Wjo?rel=0&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 30 Oct 2015 12:05:12 GMT</pubDate></item><item><title>Technology for Saving Time</title><link>https://domchristie.co.uk/posts/technology-for-saving-time/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/technology-for-saving-time/</guid><description>&lt;p&gt;My new thing is to listen to Danish radio in the morning in the hope that it will improve my Danish language listening skills. At the moment I can only pick up the odd word in each sentence, but there was an interview (in English) with Prem Rawat that caught my ear, which included this:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I think we are really out of touch with ourselves. We’re in touch with everything else: this account, and that account, and our phones. Things that were supposed to &lt;em&gt;save us us time&lt;/em&gt; may or may not save time, but they definitely &lt;em&gt;occupy that free time&lt;/em&gt; we were promised.&lt;/p&gt;
&lt;cite&gt;Prem Rawat &lt;span class=&quot;byline lower&quot;&gt;on&lt;/span&gt; DRP1’s &lt;a href=&quot;http://www.dr.dk/radio/ondemand/p1/sproglaboratoriet-2015-10-16#!/24:57&quot;&gt;Sproglaboratoriet&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;This reminded me of something Mark Steel said when he was on The Infinite Monkey Cage show. He reckoned that the problems lie with the “social mechanisms” that employ the science, rather than the science itself:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;In the early 1970s, there were two things that we were promised … One was that space travel would go on and on, and by now we’d &lt;em&gt;certainly&lt;/em&gt; be on Mars. But the other thing was that new technology would mean that we would have this crisis of having &lt;em&gt;so much leisure&lt;/em&gt;, because &lt;em&gt;everything&lt;/em&gt; would done by machinery … what on earth do we do with all the time? As we know, the average working week now in Britain is longer than it was back then.&lt;/p&gt;
&lt;cite&gt;Mark Steel &lt;span class=&quot;byline lower&quot;&gt;on&lt;/span&gt; BBC Radio 4’s &lt;a href=&quot;http://www.bbc.co.uk/programmes/b00sx2qt&quot;&gt;The Infinite Monkey Cage Series 2 Ep. 4&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Tue, 27 Oct 2015 09:30:25 GMT</pubDate></item><item><title>The Essence of Programming</title><link>https://domchristie.co.uk/posts/the-essence-of-programming/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-essence-of-programming/</guid><description>&lt;blockquote&gt;&lt;p&gt;What I mean is that if you really want to understand something, the best way is to try and explain it to someone else. That forces you to sort it out in your own mind. And the more slow and dim-witted your pupil, the more you have to break things down into more and more simple ideas. And that’s really the essence of programming. By the time you’ve sorted out a complicated idea into little steps that even a stupid machine can deal with, you’ve certainly learned something about it yourself. The teacher usually learns more than the pupil. Isn’t that true?&lt;/p&gt;&lt;cite&gt;&lt;span class=&quot;byline lower&quot;&gt;from&lt;/span&gt; Dirk Gently’s Holistic Detective Agency &lt;span class=&quot;byline lower&quot;&gt;by&lt;/span&gt; Douglas Adams&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Fri, 02 Oct 2015 14:20:23 GMT</pubDate></item><item><title>This and That, and That</title><link>https://domchristie.co.uk/posts/this-and-that-and-that/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/this-and-that-and-that/</guid><description>&lt;h2&gt;Danish&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;The Danish language has collapsed into meaningless guttural sounds.&lt;/p&gt;&lt;cite&gt;From &lt;a href=&quot;https://www.youtube.com/watch?v=s-mOy8VUEBk&quot;&gt;a sketch&lt;/a&gt; on Norwegian TV show, Uti Vår Hage&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;I have been teaching myself the Danish language with the Duolingo app since January, and so far it has been pretty fun—albeit a little difficult at times. A couple of favourite words so far:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;vandmand&lt;/em&gt; is the Danish word for &lt;em&gt;jellyfish&lt;/em&gt;, which literally translates to &lt;em&gt;water man&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;&lt;a href=&quot;https://translate.google.co.uk/#da/en/sædvanligvis&quot;&gt;sædvanligvis&lt;/a&gt;&lt;/em&gt; means &lt;em&gt;usually&lt;/em&gt; and is very satisfying to say/hear&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;&lt;a href=&quot;https://translate.google.co.uk/#da/en/medlemmerne&quot;&gt;medlemmerne&lt;/a&gt;&lt;/em&gt;, meaning &lt;em&gt;the members&lt;/em&gt;—it’s a bit difficult to pronounce, but reminds me of &lt;em&gt;Mahna Mahna.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/8N_tupPBtWQ?rel=0&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;I had a chance to practice some of Danish skills when I visited Copenhagen with Helen and family in April. We had a great time, ate some tasty food (apart from the burnt onion ash!), and I had a chance to catch up with &lt;a href=&quot;https://twitter.com/heymatt_j&quot;&gt;my old friend Matt&lt;/a&gt; (aka Milhouse).&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21389929606/in/dateposted-public/&quot; title=&quot;2014-11_4410_lomo-lca_kodak-portra-400_33.jpg&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/738/21389929606_1f0db276d8.jpg&quot; alt=&quot;2014-11_4410_lomo-lca_kodak-portra-400_33.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Had to be done. Nyhavn, Copenhagen. April 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Sardinia&lt;/h2&gt;
&lt;p&gt;Whilst most the UK were struggling through the sweaty June/July heatwave, Helen and I were lazying by the beach in Sardinia. The location was &lt;a href=&quot;https://instagram.com/p/4kLfGeRFLr/&quot;&gt;spectacular&lt;/a&gt;, so here is a picture of a food van:&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21160007479/in/dateposted-public/&quot; title=&quot;2015-07_6242_olympus-mju-ii_kodak-gold-200_19.jpg&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5806/21160007479_4d875700ae.jpg&quot; alt=&quot;2015-07_6242_olympus-mju-ii_kodak-gold-200_19.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Blue van. Blue bins. Alghero, Sardinia. July 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;France&lt;/h2&gt;
&lt;p&gt;At the end of July, Helen and I visited France. Our first stop was Nogent-le-Rotrou, a seemingly sleepy town in the Perche region, where we attended the wedding of one of Helen’s old work friends. Once again, another stunning location, overlooking the endless French countryside, so here is a picture of a quiet junction:&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21158698280/in/dateposted-public/&quot; title=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_00.jpg&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/652/21158698280_b97dcee5f6.jpg&quot; alt=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_00.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;An Espace indicates to go left. Nogent-le-Routrou, July 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;After that we spend a few nights in Paris. We were fortunate enough to catch the final stage of the Tour de France on the day we arrived, including a fleeting glimpse of Chris Froome.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21218031610/in/dateposted-public/&quot; title=&quot;R0000840.jpg&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/698/21218031610_dfa28f906d.jpg&quot; alt=&quot;R0000840.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Men complete a bike ride. (Froome in the Yellow.) Paris, July 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21159945299/in/dateposted-public/&quot; title=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_09.jpg&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/620/21159945299_d8f98a78ca.jpg&quot; alt=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_09.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Meeeeeetro traaaaain. Paris, July 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21159951069/in/dateposted-public/&quot; title=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_14.jpg&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5766/21159951069_fdba30ac17.jpg&quot; alt=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_14.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Greenery, ornate balconies, and signage. Paris, July 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/20724134424/in/dateposted-public/&quot; title=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_17.jpg&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5825/20724134424_307dd7c25e.jpg&quot; alt=&quot;2015-07_6243_olympus-mju-ii_kodak-ultramax-400_17.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;More ornate balconies. Paris, July 2015.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Finally&lt;/h2&gt;
&lt;p&gt;I will miss this gentleman a lot.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/21218289080/in/dateposted/&quot; title=&quot;R0000583.jpg&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5782/21218289080_e303a9f1da.jpg&quot; alt=&quot;R0000583.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some of James’ excellent musical creations can be heard on &lt;a href=&quot;https://soundcloud.com/whitworf&quot;&gt;his soundcloud page&lt;/a&gt;. &lt;a href=&quot;https://soundcloud.com/whitworf/mark-tyrone&quot;&gt;Mark &amp;#x26; Tyrone&lt;/a&gt; (about a haphazard Wagamana waiter) is a particular favourite of mine.&lt;/p&gt;
&lt;p&gt;A campaign has been set up to complete James’ second album. To donate, visit &lt;a href=&quot;https://www.indiegogo.com/projects/completing-james-album#/story&quot;&gt;the campaign page&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;
  &lt;/p&gt;</description><pubDate>Fri, 18 Sep 2015 15:02:23 GMT</pubDate></item><item><title>Turbine</title><link>https://domchristie.co.uk/posts/turbine/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/turbine/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/18619193288&quot; title=&quot;Turbine by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://c1.staticflickr.com/1/265/18619193288_35da9ed51d.jpg&quot; alt=&quot;Turbine&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Cleaning up after &lt;a href=&quot;http://www.theguardian.com/world/2015/jun/13/climate-change-activists-occupy-tate-moderns-turbine-hall&quot;&gt;activists occupy Tate Modern’s Turbine Hall&lt;/a&gt;. June 2015.&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Sun, 14 Jun 2015 15:57:51 GMT</pubDate></item><item><title>Graphical Integrity in Data Visualisations</title><link>https://domchristie.co.uk/posts/graphical-integrity-in-data-visualisations/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/graphical-integrity-in-data-visualisations/</guid><description>&lt;p&gt;This infographic, highlighting quirks of the UK voting system, recently popped up in my Twitter feed. Whilst the accompanying article makes some valid points, the graphic is rather inaccurate.&lt;/p&gt;
&lt;div&gt;
&lt;figure&gt;&lt;a href=&quot;https://domchristie.s3.amazonaws.com/may2015-votes-seats-original.png&quot;&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/may2015-votes-seats-original.png&quot; alt=&quot;Infographic of forecast votes-to-seats for Ukip, Lib Dems, Greens, and SNP&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Data Visualisation taken from &lt;a href=&quot;http://may2015.com/featured/would-you-like-5-million-votes-and-4-seats-or-1-million-votes-and-56-seats/&quot;&gt;May2015: Would you like 5 million votes and 4 seats, or 1 million votes and 56 seats?&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Firstly, it uses circles (of two dimensions) to represent one-dimensional data. Edward Tufte discusses this in The Visual Display of Quantitative Information:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;There are considerable ambiguities in how people perceive a two-dimensional surface and then convert that perception into a one-dimensional number. Changes in physical area on the surface of a graphic do not reliably produce appropriately proportional changes in perceived areas.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;In this instance, the designer has varied the radius/diameter of the circles, which results in a surface area that exaggerates the data. For example, compare the circles for the Green Party and the SNP. If the Green Party circle represents 1 unit-squared, then you’d expect the SNP’s circle to be 56 units-squared. Instead, it is 3136 units-squared—56-times greater than it should be.&lt;/p&gt;
&lt;p&gt;Secondly, it encourages comparisons between values on different scales: percentage of votes, and number of seats.&lt;/p&gt;
&lt;p&gt;The graphic gives the impression that the Lib Dems &lt;strong&gt;gain&lt;/strong&gt; considerably from the voting system: 8% votes → 26 seats. 26 seats actually represents just 4% of the total seats (650), so their votes are &lt;strong&gt;effectively halved&lt;/strong&gt;! This distortion is also observed when comparing the Lib Dems’ “votes” circle to the SNP’s “seats” circle. The SNP’s 56 seats (8.61%) should be comparable to the Lib Dems votes (8%). It isn’t.&lt;/p&gt;
&lt;div&gt;
&lt;figure&gt;&lt;a href=&quot;https://domchristie.s3.amazonaws.com/may2015-votes-seats-annotated.png&quot;&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/may2015-votes-seats-annotated.png&quot; alt=&quot;Infographic of forecast votes-to-seats for Ukip, Lib Dems, Greens, and SNP, highlighting inaccuracies&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Annotated graphic highlighting distortions. The dark blue circle shows how big the SNP’s circle would be if areas were proportionate.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;What’s more, there is a second graphic (not re-published here), making the same votes-to-seats comparisons but with the Labour, Conservative, and Ukip parties. However, this is on a different scale to the previous one, making any further comparisons impossible.&lt;/p&gt;
&lt;p&gt;It would be more accurate to make comparisons based on percentages of seats, and include all the data in a single graphic. Perhaps a simple table would suffice?&lt;/p&gt;
&lt;p&gt;The following table attempts to convey how much each party is set to gain/lose because of the voting system based on the forecast. A ratio greater than 1 indicates that a party gains from the system; ratio less than 1 indicates that a party loses from the system.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Party&lt;/th&gt;
      &lt;th class=&quot;number&quot;&gt;% of Votes&lt;/th&gt;
      &lt;th class=&quot;number&quot;&gt;% of Seats&lt;/th&gt;
      &lt;th class=&quot;number&quot;&gt;
        Ratio
        &lt;div class=&quot;muted&quot;&gt;
          &lt;small&gt;% Seats / % Votes&lt;/small&gt;
        &lt;/div&gt;
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Labour&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;33&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;42.31&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;1.28&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Conservatives&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;31&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;40.92&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;1.32&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Ukip&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;15&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.62&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.04&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Lib Dems&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;8&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;4.00&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.50&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Green&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;7&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.15&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.02&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SNP&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;4&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;8.62&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;2.15&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Ratios can be transformed into “Advantages” by taking logarithms: positive values indicate gain, negative values indicate loss.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Party&lt;/th&gt;
      &lt;th class=&quot;number&quot;&gt;% of Votes&lt;/th&gt;
      &lt;th class=&quot;number&quot;&gt;% of Seats&lt;/th&gt;
      &lt;th class=&quot;number&quot;&gt;
        Advantage
        &lt;div class=&quot;muted&quot;&gt;
          &lt;small&gt;log&lt;sub&gt;2&lt;/sub&gt;(% Seats / % Votes)&lt;/small&gt;
        &lt;/div&gt;
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Labour&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;33&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;42.31&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.36 &lt;!-- log2 1.28205128205128205125 --&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Conservatives&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;31&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;40.92&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.40 &lt;!-- log2 1.32009925558312655083 --&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Ukip&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;15&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.62&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;-4.61 &lt;!--log2  0.04102564102564102564 --&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Lib Dems&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;8&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;4.00&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;-1.00 &lt;!-- log2 0.50 --&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Green&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;7&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;0.15&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;-5.51 &lt;!-- log2 0.02197802197802197802 --&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SNP&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;4&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;8.62&lt;/td&gt;
      &lt;td class=&quot;number&quot;&gt;1.11&lt;!-- log2 2.1538461538461538461 --&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;From these tables we can deduce that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Labour and the Conservatives are set to gain a little from the voting system&lt;/li&gt;
  &lt;li&gt;The SNP would gain as much proportionally as the Lib Dems lose: the voting system effectively doubles the SNP’s seats, and halves the Lib Dems’&lt;/li&gt;
  &lt;li&gt;Ukip and the Greens are set to lose out the most, significantly more than any other loses or gains&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Got feedback? Email me: &lt;a href=&quot;mailto:christiedom@gmail.com&quot;&gt;christiedom@gmail.com&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 21 Feb 2015 15:50:00 GMT</pubDate></item><item><title>Emergency Use Only</title><link>https://domchristie.co.uk/posts/emergency-use-only/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/emergency-use-only/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15210955421&quot; title=&quot;14-08_2118_lomo-lca_kodak-colorplus-200_20.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5563/15210955421_00e01173ac.jpg&quot; alt=&quot;14-08_2118_lomo-lca_kodak-colorplus-200_20.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;London, August 2014&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Thu, 11 Dec 2014 21:47:46 GMT</pubDate></item><item><title>David Heinemeier Hansson on Ambition</title><link>https://domchristie.co.uk/posts/david-heinemeier-hansson-on-ambition/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/david-heinemeier-hansson-on-ambition/</guid><description>&lt;blockquote&gt;
&lt;p&gt;It might sound funny, but I’m not a very ambitious person. When it comes to software and products, I have a very low bar in terms of ambition level. I feel like there is so much stuff that is so poor, where the things you have to do to improve, just have to be just a little bit better.&lt;/p&gt;
&lt;cite&gt;David Heinemeier Hansson &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=lBfVxBj61z0&quot;&gt;Jellyvision Q&amp;#x26;A with DHH &amp;#x26; Jason Fried&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Sun, 07 Dec 2014 21:18:47 GMT</pubDate></item><item><title>Attention</title><link>https://domchristie.co.uk/posts/attention/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/attention/</guid><description>&lt;blockquote&gt;&lt;p&gt;The gift of attention is perhaps the most valuable. Attention may seem like an easy gift to give, but it is not; it is the scarcest resource available because its quantities are limited and nonrenewable. We can’t produce more attention, and there are ever more things vying for it each day.&lt;/p&gt;&lt;cite&gt;Frank Chimero &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://read.shapeofdesignbook.com/chapter10.html&quot;&gt;The Shape of Design&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Tue, 07 Oct 2014 11:37:40 GMT</pubDate></item><item><title>The Not-So-Straight &amp; The Not-So-Perfect</title><link>https://domchristie.co.uk/posts/the-not-so-straight-the-not-so-perfect/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-not-so-straight-the-not-so-perfect/</guid><description>&lt;blockquote&gt;&lt;p&gt;The not-so-straight and the not-so-perfect is the lovely thing of life. And there’s somebody out there trying to make the world straight and perfect…When the world will be straight and perfect in their eyes, will that be straight and perfect, or will it be worse?&lt;/p&gt;&lt;cite&gt;&lt;span class=&quot;byline lower&quot;&gt;from&lt;/span&gt; &lt;a href=&quot;http://vimeo.com/103475540&quot;&gt;Analogue People in a Digital Age&lt;/a&gt; &lt;span class=&quot;byline lower&quot;&gt;by&lt;/span&gt; Twopair Films&lt;/cite&gt;&lt;/blockquote&gt;
&lt;iframe src=&quot;//player.vimeo.com/video/103475540?title=0&amp;#x26;byline=0&amp;#x26;portrait=0&amp;#x26;color=ffffff&quot; style=&quot;--width: 500; --height: 281&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Mon, 22 Sep 2014 11:01:59 GMT</pubDate></item><item><title>Aphex Twin on Smartphones</title><link>https://domchristie.co.uk/posts/aphex-twin-on-smartphones/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/aphex-twin-on-smartphones/</guid><description>&lt;blockquote&gt;&lt;p&gt;I don’t have any phones. They’re just not good for anything. They’re handy for loads of stuff, but I can’t think of anything that’s better because you’ve got them. I think there’s a risk of people becoming zombies with Facebook and social media. It’s really awful, that side of things.&lt;/p&gt;&lt;cite&gt;&lt;a href=&quot;http://www.rollingstone.com/music/features/aphex-twin-on-new-syro-lp-im-feeling-really-horny-about-it-and-very-smug-20140903#ixzz3DlgBVEbL &quot;&gt;Aphex Twin &lt;span class=&quot;byline lower&quot;&gt;discusses&lt;/span&gt; ‘Syro’&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Fri, 19 Sep 2014 12:32:04 GMT</pubDate></item><item><title>Barcelona 2014</title><link>https://domchristie.co.uk/posts/barcelona-2014/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/barcelona-2014/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15233546465&quot; title=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_13.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3838/15233546465_ea34915325.jpg&quot; alt=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_13.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15262591026&quot; title=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_05.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2941/15262591026_153865c6a3.jpg&quot; alt=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_05.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15233554935&quot; title=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_35.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5594/15233554935_f643b8a91d.jpg&quot; alt=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_35.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15046843340&quot; title=&quot;14-08_2116_olympus-mju-ii_kodak-gold-200_20.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5596/15046843340_ac018d3d64.jpg&quot; alt=&quot;14-08_2116_olympus-mju-ii_kodak-gold-200_20.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15210517076&quot; title=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_09.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3858/15210517076_a9f33d461b.jpg&quot; alt=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_09.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/15233552795&quot; title=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_32.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3907/15233552795_3ee30e78de.jpg&quot; alt=&quot;14-08_2117_lomo-lca_kodak-colorplus-200_32.jpg&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;More photos in the &lt;a href=&quot;https://www.flickr.com/photos/domchristie/sets/72157647570328421/&quot;&gt;Barcelona 2014 set&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Fri, 19 Sep 2014 06:34:09 GMT</pubDate></item><item><title>Preferences in User Interface Design</title><link>https://domchristie.co.uk/posts/preferences-in-user-interface-design/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/preferences-in-user-interface-design/</guid><description>&lt;p&gt;Jef Raskin on “Modes, User-Preference Settings, and Temporary Modes”, in &lt;a href=&quot;http://www.amazon.co.uk/The-Humane-Interface-Directions-Interactive/dp/0201379376&quot;&gt;The Humane Interface&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Facilities for setting user preferences constitute an example of modes and are a major source of frustration. Ironically, these features are usually touted as a benefit. Present user interfaces are often so difficult to use that a user may feel an urge to rearrange them. Microsoft specifically recommends that such facilities be provided: “Users, because of their widely varying skills and preferences, must be able to personalize aspects of their interface … such as color, fonts, or other options.” [from Microsoft’s Windows Interface Guidelines, 1995] &lt;/p&gt;
&lt;p&gt;… By providing preferences, we burden users with a task extraneous to their job function. … &lt;em&gt;Time spent in learning and operating the personalization features is time mostly wasted from the task at hand&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;… Customization sounds nice, democratic, open-ended, and full of freedom and joy for the user, but I am unaware of any studies that show that it increases productivity or improves &lt;em&gt;objective&lt;/em&gt; measures of usability or learnability. Adding customization certainly makes a system more complex and more difficult to learn. I suspect that if you were to take a user survey, more people than not would be in favor of lots of personalizable features … [but as] has been observed in a number of experiments, &lt;em&gt;an interface that optimizes productivity is not necessarily an interface that optimises subjective ratings&lt;/em&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;See also: &lt;a href=&quot;https://gettingreal.37signals.com/ch06_Avoid_Preferences.php&quot;&gt;Avoid Preferences&lt;/a&gt; from &lt;a href=&quot;https://gettingreal.37signals.com/toc.php&quot;&gt;Getting Real&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(I’m looking at you, Slack)&lt;/p&gt;</description><pubDate>Sat, 13 Sep 2014 14:45:15 GMT</pubDate></item><item><title>Array Controllers in Ember.js</title><link>https://domchristie.co.uk/posts/array-controllers-in-ember-js/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/array-controllers-in-ember-js/</guid><description>&lt;p&gt;An array controller is a wrapper for a collection of objects, and provides convenient methods for dealing with its contents.&lt;/p&gt;
&lt;p&gt;An array controller’s &lt;code&gt;model&lt;/code&gt; is typically set in a route, for example:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;App.IndexRoute &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Ember.Route.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      {name: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;red&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      {name: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;yellow&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      {name: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;blue&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// (The Index ArrayController is setup implicitly)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Setting an array controller’s &lt;code&gt;model&lt;/code&gt; sets up its &lt;code&gt;content&lt;/code&gt; property, which forms the basis for other properties and methods.&lt;/p&gt;
&lt;h2&gt;arrangedContent&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;arrangedContent&lt;/code&gt; is an important property, defined as “the array that the [array controller] pretends to be”. It provides a way for sorted/filtered content to be stored separately from the original &lt;code&gt;content&lt;/code&gt;. In this way, sorting/filtering is not destructive, and the content (in its original form) can still be retrieved.&lt;/p&gt;
&lt;p&gt;By default, when an array controller has no &lt;code&gt;sortProperties&lt;/code&gt;, &lt;code&gt;arrangedContent&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt; are the same. When &lt;code&gt;sortProperties&lt;/code&gt; are added, the sorted content is stored in &lt;code&gt;arrangedContent&lt;/code&gt; whilst the original &lt;code&gt;content&lt;/code&gt; remains untouched.&lt;/p&gt;
&lt;p&gt;It’s important to note that &lt;strong&gt;an array controller should be treated just like an array&lt;/strong&gt;, with its items referencing those in &lt;code&gt;arrangedContent&lt;/code&gt;. Accessing items on an array controller itself, is &lt;em&gt;effectively&lt;/em&gt; the same as accessing items in &lt;code&gt;arrangedContent&lt;/code&gt; (an important difference is discussed in below).&lt;/p&gt;
&lt;p&gt;This is best illustrated with some examples. Given the route above, the following &lt;code&gt;#each&lt;/code&gt; loops all result in the same output:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index&lt;/code&gt; template:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each}} {{name}} {{/each}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each content}} {{name}} {{/each}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each arrangedContent}} {{name}} {{/each}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.jsbin.com/nuzoja/1/edit?html,js,output&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://emberjs.jsbin.com/nuzoja/1&quot;&gt;http://emberjs.jsbin.com/nuzoja/1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Setting &lt;code&gt;sortProperties&lt;/code&gt; results in sorted output from &lt;code&gt;arrangedProperty&lt;/code&gt; and therefore from the array controller instance itself:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;App.IndexController &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Ember.ArrayController.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  sortProperties: [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;index&lt;/code&gt; template:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{!-- Sorted by name --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{!-- Not Sorted --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each content}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{!-- Sorted by name --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each arrangedContent}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;caption&quot;&gt;&lt;a href=&quot;http://emberjs.jsbin.com/nuzoja/2/edit?html,js,output&quot;&gt;http://emberjs.jsbin.com/nuzoja/2/edit&lt;/a&gt;&lt;/div&gt;
&lt;h2&gt;Item Controllers&lt;/h2&gt;
&lt;p&gt;Adding an &lt;code&gt;itemController&lt;/code&gt; property to an array controller wraps each item in an instance of the referenced controller. However, this only applies when accessing items through the array controller instance itself. Items accessed via &lt;code&gt;arrangedContent&lt;/code&gt; or &lt;code&gt;content&lt;/code&gt; remain unwrapped. This is the key difference when accessing items via &lt;code&gt;arrangedContent&lt;/code&gt; versus accessing them via the array controller instance itself.&lt;/p&gt;
&lt;p&gt;The following example demonstrates this concept:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;App.IndexController &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Ember.ArrayController.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  itemController: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;color&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;App.ColorController &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Ember.ObjectController.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  isActive: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;index&lt;/code&gt; template:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{!-- Names rendered --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;  {{#if isActive}} {{name}} {{/if}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{/each}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{!-- Nothing rendered --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each content}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;  {{#if isActive}} {{name}} {{/if}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{/each}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{!-- Nothing rendered --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{#each arrangedContent}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;  {{#if isActive}} {{name}} {{/if}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #e1e4e8&quot;&gt;{{/each}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.jsbin.com/nuzoja/3/edit?html,js,output&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://emberjs.jsbin.com/nuzoja/3/edit&quot;&gt;http://emberjs.jsbin.com/nuzoja/3/edit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nothing is rendered in the loops that iterate over &lt;code&gt;content&lt;/code&gt; or &lt;code&gt;arrangedContent&lt;/code&gt; because the items are not wrapped in an item controller and therefore &lt;code&gt;isActive&lt;/code&gt; is inaccessible.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;{{#each itemController=&apos;…&apos;}}&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;{{#each}}&lt;/code&gt; helpers, when supplied with an &lt;code&gt;itemController&lt;/code&gt; property, wrap each item in &lt;strong&gt;a new instance&lt;/strong&gt; of the referenced controller. This operates entirely independently from the &lt;code&gt;itemController&lt;/code&gt; property on an array controller: an array controller will not have access to any item controller created via an &lt;code&gt;{{#each}}&lt;/code&gt; helper.&lt;/p&gt;
&lt;p&gt;This becomes particularly important when implementing a computed property on an array controller that depends on properties on an item controller. See &lt;a href=&quot;http://emberjs.jsbin.com/nuzoja/9/edit?html,js,output&quot;&gt;the example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://emberjs.com/api/classes/Ember.ArrayController.html&quot;&gt;Ember.ArrayController Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ember.guru/2014/hidden-features-of-the-each-aka-loopedy-loop-helper&quot;&gt;The &lt;code&gt;#each&lt;/code&gt; helper post&lt;/a&gt; on ember.guru&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.confreaks.com/videos/3457-emberconf2014-array-computed-properties&quot;&gt;Array Computed Properties&lt;/a&gt; talk by David Hamilton&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Fri, 29 Aug 2014 11:58:18 GMT</pubDate></item><item><title>Portable</title><link>https://domchristie.co.uk/posts/portable/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/portable/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14917608635&quot; title=&quot;14-07_6984_lomo-lca_kodak-gold-200_0_.jpg by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3859/14917608635_0ee7d263a8.jpg&quot; alt=&quot;14-07_6984_lomo-lca_kodak-gold-200_0_.jpg&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;London, 2014&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Fri, 15 Aug 2014 13:28:17 GMT</pubDate></item><item><title>Don Norman’s Law</title><link>https://domchristie.co.uk/posts/don-norman-s-law/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/don-norman-s-law/</guid><description>&lt;blockquote&gt;&lt;p&gt;If you think something is clever and sophisticated beware—it is probably self-indulgence.&lt;/p&gt;&lt;cite&gt;Don Norman &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; The Psychology of Everyday Things&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Fri, 18 Jul 2014 04:54:50 GMT</pubDate></item><item><title>The Putter</title><link>https://domchristie.co.uk/posts/the-putter/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-putter/</guid><description>&lt;iframe src=&quot;//player.vimeo.com/video/98953952?title=0&amp;#x26;byline=0&amp;#x26;portrait=0&amp;#x26;color=ffffff&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;A short film about assembling scissors at &lt;a href=&quot;http://www.ernestwright.co.uk&quot;&gt;Ernest Wright and Son&lt;/a&gt; (via &lt;a href=&quot;http://www.plucky.be/blog/2014/7/4/the-putter-a-putter-togetherer-of-scissors&quot;&gt;Vicki Turner&lt;/a&gt;).&lt;/p&gt;</description><pubDate>Sat, 05 Jul 2014 07:38:21 GMT</pubDate></item><item><title>David Shrigley Tableware</title><link>https://domchristie.co.uk/posts/david-shrigley-tableware/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/david-shrigley-tableware/</guid><description>&lt;p&gt;Absolutely love these pieces by David Shrigley for &lt;a href=&quot;https://www.sketch.uk.com/David_Shrigley_intro.php&quot;&gt;Soho’s Sketch restaurant&lt;/a&gt;. Seen in &lt;a href=&quot;http://www.cityam.com/1403547146/david-shrigley-sketch-fourth-plinth&quot;&gt;an interview with Shrigley&lt;/a&gt; in City A.M’s Bespoke magazine.&lt;/p&gt;
&lt;img src=&quot;https://domchristie.s3.amazonaws.com/ceramics0.jpg&quot; alt=&quot;Salt and pepper shakers with &amp;#x27;Dust&amp;#x27;, &amp;#x27;Dirt&amp;#x27;, and &amp;#x27;Nothing&amp;#x27; written on them&quot;&gt;
&lt;img src=&quot;https://domchristie.s3.amazonaws.com/ceramics3.jpg&quot; alt=&quot;Shrigley teapot and accessories&quot;&gt;</description><pubDate>Tue, 01 Jul 2014 05:36:40 GMT</pubDate></item><item><title>Bali 2014</title><link>https://domchristie.co.uk/posts/bali-2014/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/bali-2014/</guid><description>&lt;p&gt;A few thoughts and photos from my trip to Bali with Helen last month.&lt;/p&gt;
&lt;h2&gt;Sanur and Ubud&lt;/h2&gt;
&lt;p&gt;Our first stay was right on the beach, in the resort of &lt;strong&gt;Sanur&lt;/strong&gt;. It’s a quiet place, particularly compared to Denpasar (the capital) and Ubud, our second destination…&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14296523638&quot; title=&quot;14-05_5803_kodak-disposable_kodak-disposable-800_32 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3881/14296523638_590afd3f17.jpg&quot; alt=&quot;14-05_5803_kodak-disposable_kodak-disposable-800_32&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;The view from our hotel beach in Sanur, looking south. (Excuse the photo quality, it was taken on a disposable.)&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14479707901&quot; title=&quot;14-05_5798_olympus-mju-v_kodak-200-8_22 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3866/14479707901_4df417717d.jpg&quot; alt=&quot;14-05_5798_olympus-mju-v_kodak-200-8_22&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;The view at breakfast: a fisherman wading out at sea.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Ubud&lt;/strong&gt; is further inland, about 40 minutes north of Sanur. It’s known for its arts scene and there were plenty of market stalls selling handcrafted goods. We of course took our chance to do a bit of bartering! (We bought a couple of kites and a small wooden owl!)&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14296487220&quot; title=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_30 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3907/14296487220_ea3e2b703b.jpg&quot; alt=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_30&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;A market seller un Ubud prepares flower petals to sell for for Hindu offerings.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;We stayed at &lt;a href=&quot;http://www.comohotels.com/umaubud/uma-como-ubud&quot;&gt;Uma&lt;/a&gt;, a luxury hotel located a short distance from the centre. The whole experience was pretty amazing: the room, the food, and the pool were all top notch!&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14460001666&quot; title=&quot;14-05_5803_kodak-disposable_kodak-disposable-800_01 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5529/14460001666_83dba41e79.jpg&quot; alt=&quot;14-05_5803_kodak-disposable_kodak-disposable-800_01&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;On our last morning we went on a short guided walk through the local rice fields in Ubud.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Temples&lt;/h2&gt;
&lt;p&gt;Hinduism is a huge part of Balinese life, so there are temples (&lt;em&gt;Pura&lt;/em&gt;) and offerings everywhere. Many temples are in spectacular locations: on the edge of a cliff, on a lake, or on a rock heading out to sea.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14395488802&quot; title=&quot;Uluwatu Temple by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3854/14395488802_24fa8ed7da.jpg&quot; alt=&quot;Uluwatu Temple&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Pura Luhur Uluwatu.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14459995346&quot; title=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_35 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2901/14459995346_117cf1cbc3.jpg&quot; alt=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_35&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;The &lt;a href=&quot;http://domchristie.co.uk/posts/kecak&quot;&gt;Kecak&lt;/a&gt; dance at Pura Luhur Uluwatu.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14539395494&quot; title=&quot;14-05_5802_olympus-mju-ii_kodak-gold-200_11 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5578/14539395494_f68768812c.jpg&quot; alt=&quot;14-05_5802_olympus-mju-ii_kodak-gold-200_11&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Pura Ulun Danu Bratan.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Rice Fields&lt;/h2&gt;
&lt;p&gt;Rice fields make up a big part of the landscape in Bali. We hired a driver who took us on a trip round some windy mountain roads to check out the Jatiluwih rice terraces, the largest in Bali. The terraces were vast, and the views spectacular (unfortunately difficult to capture on camera!).&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14296505738&quot; title=&quot;14-05_5798_olympus-mju-v_kodak-200-8_29 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3850/14296505738_c79b1f9169.jpg&quot; alt=&quot;14-05_5798_olympus-mju-v_kodak-200-8_29&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14479715581&quot; title=&quot;14-05_5798_olympus-mju-v_kodak-200-8_30 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3882/14479715581_94a1f9964d.jpg&quot; alt=&quot;14-05_5798_olympus-mju-v_kodak-200-8_30&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;Activities&lt;/h2&gt;
&lt;p&gt;We went on a few guided tours to various places on the island. One of my favourites was a bike ride down a mountain. It was a great chance to explore some of the mountain villages that we’d previously driven through.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14296678397&quot; title=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_12 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2898/14296678397_a0d7acb5ca.jpg&quot; alt=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_12&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Overlooking a mountain village at the start of our bike ride. Those decorated arching bamboo poles (&lt;em&gt;Penjor&lt;/em&gt;) were up to celebrate Galungan, an annual festival celebrating the victory of good over evil.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14385606531&quot; title=&quot;Dog’s Bollocks by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2925/14385606531_a6a99b8f52.jpg&quot; alt=&quot;Dog’s Bollocks&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;The gentleman that let us have a tour of his house.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14400787181&quot; title=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_14 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3895/14400787181_f4191ae8cb.jpg&quot; alt=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_14&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;A girl at a coffee plantation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;We also went white water rafting, and snorkelling, which included a boat ride on one of these:&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14479727371&quot; title=&quot;14-05_5803_kodak-disposable_kodak-disposable-800_24 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5278/14479727371_5eac9a175c.jpg&quot; alt=&quot;14-05_5803_kodak-disposable_kodak-disposable-800_24&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Jukung boats at Padang Bai, where we explored the coral reef and swam with the fishes.&lt;/figcaption&gt;&lt;figure&gt;
&lt;h2&gt;Food&lt;/h2&gt;
&lt;p&gt;The food in Bali was pretty good. Lots of rice and some really good barbecued fish and meat. Unfortunately, no matter how careful we were with what we ate, we still managed to get a bout of &lt;em&gt;Bali Belly&lt;/em&gt;, which was rather uncomfortable for the last few days of the holiday (and plane ride!). Luckily it didn’t really stop us from doing much.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14479735881&quot; title=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_22 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3846/14479735881_fe334df7b2.jpg&quot; alt=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_22&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Barbecued ribs at Naughty Nuri’s.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14481890094&quot; title=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_20 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5546/14481890094_f2e4c0fa43.jpg&quot; alt=&quot;14-05_5875_olympus-mju-ii_kodak-gold-200_20&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;The bar at Naughty Nuri’s.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Monkeys&lt;/h2&gt;
&lt;p&gt;We saw quite a few of these mischievous monkeys, particularly around Uluwatu. They will grab almost anything (mostly sunglasses), even flip flops off your feet! Fortunately we had been forewarned, and left all our loose items in the car.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14296509278&quot; title=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_26 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5523/14296509278_67c44a0940.jpg&quot; alt=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_26&quot;&gt;&lt;/a&gt;&lt;/figure&gt;&lt;/figure&gt;&lt;/figure&gt;</description><pubDate>Mon, 30 Jun 2014 07:30:24 GMT</pubDate></item><item><title>Put Things In Their Places: Benjamin Franklin’s Schedule</title><link>https://domchristie.co.uk/posts/put-things-in-their-places-benjamin-franklin-s-schedule/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/put-things-in-their-places-benjamin-franklin-s-schedule/</guid><description>&lt;figure&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/benjamin-franklin-schedule.jpg&quot; alt=&quot;Benjamin Franklin’s Schedule&quot;&gt;&lt;figcaption&gt;via &lt;a href=&quot;https://www.flickr.com/photos/nickbilton/3779169741/&quot;&gt;Nick Bilton&lt;/a&gt; &amp;#x26; &lt;a href=&quot;https://idonethis.com/the-busy-persons-guide-done-list/&quot;&gt;The Busy Person&apos;s Guide to the Done List&lt;/a&gt; by &lt;a href=&quot;https://idonethis.com&quot;&gt;iDoneThis&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Sun, 08 Jun 2014 20:00:50 GMT</pubDate></item><item><title>Hong Kong 2014</title><link>https://domchristie.co.uk/posts/hong-kong-2014/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/hong-kong-2014/</guid><description>&lt;p&gt;Here are a few thoughts and photos from my trip to Hong Kong with Helen last month.&lt;/p&gt;
&lt;h2&gt;Skyline&lt;/h2&gt;
&lt;p&gt;Hong Kong’s skyline is incredible, but I didn’t fully appreciate it until I saw a clear and uninterrupted view at night from Tsim Sha Tsui (TST), Kowloon (below). Up until then, I’d been most amazed by the unmissable apartment blocks. Each block is slightly different, decorated by windows, air conditioning units, and washing lines.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14344141981&quot; title=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_35 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2899/14344141981_1fd2fbd68f.jpg&quot; alt=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_35&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Hong Kong Island from TST.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160810259&quot; title=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_11 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2900/14160810259_ba71c7c576_c.jpg&quot; alt=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_11&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Apartment blocks and escalator.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Trams and Markets&lt;/h2&gt;
&lt;p&gt;We took a tram ride from Central Hong Kong to Shau Kei Wan on the east-side of the island. It was a great way to get a feel for the city, and cheap too (2.30HKD ~ 18p!). The windows can be pushed all the way down, so (if it’s not raining) it’s a handy way to take a few pictures.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160975237&quot; title=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_22 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2906/14160975237_ebf9905bf6.jpg&quot; alt=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_22&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160806169&quot; title=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_27 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2925/14160806169_e6f6b10446.jpg&quot; alt=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_27&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;At Shau Kei Wan, we were met by a fish and grocery market, where it was common to see live fish flapping about in polystyrene containers, unusual fruits, and various other bits for sale in bowls and boxes, or just laying on a trolley on the street.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160822758&quot; title=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_15 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3861/14160822758_6f04793aa3.jpg&quot; alt=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_15&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14346637994&quot; title=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_12 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3925/14346637994_b51cfa758e.jpg&quot; alt=&quot;14-05_5799_olympus-mju-ii_kodak-gold-200_12&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160832148&quot; title=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_10 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3917/14160832148_403136c799.jpg&quot; alt=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_10&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160989337&quot; title=&quot;14-05_5798_olympus-mju-v_kodak-200-8_16 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3877/14160989337_8af218c090.jpg&quot; alt=&quot;14-05_5798_olympus-mju-v_kodak-200-8_16&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;Food&lt;/h2&gt;
&lt;p&gt;To experience some authentic Cantonese food, we ventured to Mak’s Noodle, a small diner not far from where we were staying. The food was very tasty, and when a waiter noticed I was having some difficulty with the noodles, he chopped them up with a pair of scissors (thankfully I wasn’t the only one needing some help!).&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160881000&quot; title=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_01 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2932/14160881000_a1a4b1bfc1.jpg&quot; alt=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_01&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160830038&quot; title=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_03 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3867/14160830038_6f5a33f090.jpg&quot; alt=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_03&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;small&gt;That chunk of beef on top was so tender!&lt;/small&gt;&lt;/p&gt;
&lt;h2&gt;Mid-level Escalators&lt;/h2&gt;
&lt;p&gt;The street escalators are one of the coolest parts of the city. Given the hills and humidity, being able to jump on an escalator in the middle of a street was a lifesaver!&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14345888192&quot; title=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_16 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2937/14345888192_72c6f67948.jpg&quot; alt=&quot;14-05_5800_olympus-mju-ii_kodak-200-8_16&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;The Peak&lt;/h2&gt;
&lt;p&gt;For all its skyscrapers and apartment blocks, Hong Kong still has lots of greenery, and there is plenty of it to enjoy on the (steep) walk up Victoria Peak.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14160886220&quot; title=&quot;14-05_5798_olympus-mju-v_kodak-200-8_12 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2901/14160886220_1828d38199.jpg&quot; alt=&quot;14-05_5798_olympus-mju-v_kodak-200-8_12&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Thu, 05 Jun 2014 17:34:16 GMT</pubDate></item><item><title>Kecak</title><link>https://domchristie.co.uk/posts/kecak/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/kecak/</guid><description>&lt;p&gt;I’ve just come back from spending the last couple of weeks in Hong Kong and Bali. One of my favourite experiences was attending a Kecak dance (pronounced &lt;em&gt;keh-chak&lt;/em&gt;) at Pura Luhur Uluwatu, Bali. It was performed by around 50-100 people and the music was incredible.&lt;/p&gt;
&lt;iframe src=&quot;https://embed.spotify.com/?uri=spotify:track:7w1cBmNZrc15lGPtVcrgTq&quot; width=&quot;500&quot; height=&quot;80&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot;&gt;&lt;/iframe&gt;</description><pubDate>Sat, 31 May 2014 11:54:42 GMT</pubDate></item><item><title>Silverdale</title><link>https://domchristie.co.uk/posts/silverdale/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/silverdale/</guid><description>&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/14000649229&quot; title=&quot;Silverdale by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5317/14000649229_7ff85cef2d.jpg&quot; alt=&quot;Silverdale&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Wed, 14 May 2014 20:06:48 GMT</pubDate></item><item><title>Iterative Design</title><link>https://domchristie.co.uk/posts/iterative-design/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/iterative-design/</guid><description>&lt;blockquote&gt;&lt;p&gt;The design process is actually a big spiral you go through. You start exploring ideas only to come back to explore the original idea. To outsiders, it might seem like you’re going through circles, chasing your tail. But each time you go through these circles you get closer and closer to where all these things align. It’s a spiral—a fractal spiral that never ends, and the closer you get to the point where everything aligns, the more you discover, the more you realize you have to zoom in again and keep on building it. This is true for anything that can be designed. Anything can be iterated endlessly to make it better and better.&lt;/p&gt;&lt;cite&gt;Marcos Weskamp, Head Designer at Flipboard, in an  &lt;a href=&quot;http://www.fastcompany.com/3017867/most-creative-people/how-flipboards-head-designer-grapples-with-the-webs-manic-pace-of-chang&quot;&gt;interview with Fast Company&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Tue, 06 May 2014 11:33:34 GMT</pubDate></item><item><title>Wayfarer</title><link>https://domchristie.co.uk/posts/wayfarer/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/wayfarer/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/12612096484/&quot; title=&quot;Wayfarer by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2869/12612096484_a9b254274a.jpg&quot; alt=&quot;Wayfarer&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Tue, 18 Feb 2014 12:59:38 GMT</pubDate></item><item><title>Soundscape: Defrost</title><link>https://domchristie.co.uk/posts/soundscape-defrost/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/soundscape-defrost/</guid><description>&lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/132343216&amp;#x26;color=fa8072&amp;#x26;auto_play=false&amp;#x26;hide_related=false&amp;#x26;show_artwork=true&quot;&gt;&lt;/iframe&gt;</description><pubDate>Fri, 31 Jan 2014 12:53:41 GMT</pubDate></item><item><title>Simplification</title><link>https://domchristie.co.uk/posts/simplification/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/simplification/</guid><description>&lt;blockquote&gt;
  &lt;p&gt;The process of simplification is design 101, a mind-set that every design student is taught in school. But not every design student adopts it, and rarely it’s applied with the ruthless discipline practiced by Jony [Ive]. Indeed, if there’s such a thing as a single secret to what Jony Ive does, it is to follow slavishly the simplification philosophy. That approach has accounted for many of the major breakthroughs, as well as some projects that failed and others that Apple hasn’t released. Caring enough to commit the enormous time and effort to get something right has also been Jony’s hallmark, from his earliest college projects onward.&lt;/p&gt;
  &lt;cite&gt;Leander Kahney &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; Jony Ive, &lt;span class=&quot;byline lower&quot;&gt;The Genius Behind Apple’s Greatest Products&lt;/span&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Sun, 26 Jan 2014 13:26:33 GMT</pubDate></item><item><title>Knives and Forks</title><link>https://domchristie.co.uk/posts/knives-and-forks/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/knives-and-forks/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/12115047874/&quot; title=&quot;Knives and Forks by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2818/12115047874_8ae1933cff.jpg&quot; alt=&quot;Knives and Forks&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Kitchen sink, Guildford. 2006 (University 2nd year).&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I remember my friend (and housemate at the time), Julian, had his own method for dealing with this situation. He’d put on some really glitchy fast electronica (&lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;#x26;v=BxEb2FrQUbE#t=180&quot;&gt;Squarepusher&lt;/a&gt; perhaps?), and blitz it as fast as he could. Seemed to do the job, and it’s a method I often employ to get stuff done. My track of choice? &lt;a href=&quot;http://www.youtube.com/watch?v=vNOzJTIklBw&quot;&gt;Milanese - Mr. Bad News (Clark Remix)&lt;/a&gt; (NSFW).&lt;/p&gt;</description><pubDate>Fri, 24 Jan 2014 09:38:31 GMT</pubDate></item><item><title>The Things You Already Own</title><link>https://domchristie.co.uk/posts/the-things-you-already-own/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-things-you-already-own/</guid><description>&lt;blockquote&gt;&lt;p&gt;If I had a billion dollars to fund a marketing campaign, I would launch a campaign on behalf of things you already own: &lt;em&gt;Why not enjoy them today?&lt;/em&gt; Because we all have so many things that are just around—they’re in the closet, they’re in the attic, whatever—that we don’t even think about anymore because there isn’t enough room left in our brains because we are so busy processing all the exciting new developments.&lt;/p&gt;&lt;p&gt;At the end of the day, when you’re looking around at the objects in your house and you’re deciding what really has value… they’re going to be the things that have some meaning in your life.&lt;/p&gt;&lt;cite&gt;Rob Walker, New York Times columnist, in &lt;a href=&quot;http://www.objectifiedfilm.com/&quot;&gt;Objectified&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Wed, 08 Jan 2014 23:50:03 GMT</pubDate></item><item><title>Flicker</title><link>https://domchristie.co.uk/posts/flicker/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/flicker/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/11438429006/&quot; title=&quot;photo (4) by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3678/11438429006_d5ed6b8acf.jpg&quot; alt=&quot;photo (4)&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Thu, 19 Dec 2013 08:56:34 GMT</pubDate></item><item><title>RY X—Shortline</title><link>https://domchristie.co.uk/posts/ry-x-shortline/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/ry-x-shortline/</guid><description>&lt;p&gt;Really enjoying this from RY X. I first heard the title track from his EP, Berlin, on &lt;a href=&quot;http://www.youtube.com/watch?v=q2DdtkDK7w0&quot;&gt;a recent Sony TV advert&lt;/a&gt;. As it turns out, RY X is signed to Dumont Dumont, a label started by Magnus Bohman, who co-founded Imperial Recordings. Imperial’s first signing was José González, who also had a track used on &lt;a href=&quot;http://www.youtube.com/watch?v=-zOrV-5vh1A&quot;&gt;a Sony TV advert back in 2006&lt;/a&gt;. Coincidence?&lt;/p&gt;
&lt;p&gt;(Contains nudity, flashing lights, and a great synth line—which unfortunately isn’t on the record.)&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;//www.youtube-nocookie.com/embed/yxqKIxuOaOE?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Wed, 04 Dec 2013 11:00:29 GMT</pubDate></item><item><title>Mathematicians vs. Engineers</title><link>https://domchristie.co.uk/posts/mathematicians-vs-engineers/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/mathematicians-vs-engineers/</guid><description>&lt;blockquote&gt;&lt;p&gt;For the mathematician, an argument is either perfect or else it is wrong … He calls this ‘rigorous thinking.’ The typical engineer calls it ‘hair-splitting.’&lt;/p&gt;&lt;cite&gt;Thornton C. Fry, &lt;span class=&quot;byline lower&quot;&gt;Director of The Mathematics Consulting Dept., Bell Labs,&lt;/span&gt; 1941&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Taken from The Information by James Gleick, p.196.&lt;/p&gt;</description><pubDate>Mon, 11 Nov 2013 13:49:56 GMT</pubDate></item><item><title>Hotel Books</title><link>https://domchristie.co.uk/posts/hotel-books/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/hotel-books/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/10798062583/&quot; title=&quot;Hotel books by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3776/10798062583_049cc8b0eb.jpg&quot; alt=&quot;Hotel books&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Mon, 11 Nov 2013 12:30:06 GMT</pubDate></item><item><title>The Culture of Distraction</title><link>https://domchristie.co.uk/posts/the-culture-of-distraction/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-culture-of-distraction/</guid><description>&lt;p&gt;A couple of interesting talks about the fear of boredom and the anxiety of being mentally unstimulated.&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;//www.youtube-nocookie.com/embed/EzpX0TLKS9Q?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;//www.youtube-nocookie.com/embed/trVzyG4zFMU?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 18 Oct 2013 08:03:33 GMT</pubDate></item><item><title>All the Features</title><link>https://domchristie.co.uk/posts/all-the-features/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/all-the-features/</guid><description>&lt;p&gt;From Jef Raskin’s The Humane Interface:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;You can have any combination of features the Air Ministry desires, so long as you do not also require that the resulting airplane fly.&lt;/p&gt;
&lt;cite&gt;Willy Messerschmidt &lt;span class=&quot;lower byline&quot;&gt;(preeminent World War II German aircraft designer)&lt;/span&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Thu, 17 Oct 2013 07:49:33 GMT</pubDate></item><item><title>Technology that Matters</title><link>https://domchristie.co.uk/posts/technology-that-matters/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/technology-that-matters/</guid><description>&lt;p&gt;I’m sure this won’t be the last time I mention Frank Chimero’s recent article, The Inferno of Independence; there are so many good parts, but here is just a snippet. It’s something I wanted to get across in &lt;a href=&quot;http://blog.makeshift.io/post/62992606692/why-hack-an-interview-with-dom-christie&quot;&gt;my Why Hack? interview&lt;/a&gt;, but it’s articulated a lot better below:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The technology that matters only tries to change things by giving us more of what we’ve always wanted: autonomy, access, and community.&lt;/p&gt;&lt;cite&gt;Frank Chimero &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://frankchimero.com/blog/2013/09/the-inferno-of-independence/&quot;&gt;The Inferno of Independence&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;“Autonomy, access, and community.” Nailed it.&lt;/p&gt;</description><pubDate>Mon, 14 Oct 2013 20:22:37 GMT</pubDate></item><item><title>Simple Things</title><link>https://domchristie.co.uk/posts/simple-things/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/simple-things/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/10161299885/&quot; title=&quot;fence by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3793/10161299885_d672046f3c.jpg&quot; alt=&quot;fence&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote&gt;&lt;p&gt;If you can understand the ordinary, the simple things in life, the mind can be opened to foster harmony in humanity, promote harmony with nature, discipline the mind, and quiet the heart. This in turn affects our output as human beings.&lt;/p&gt;&lt;cite&gt;&lt;a href=&quot;http://the189.com/photography/simple-things-by-isabelle-bertolini/&quot;&gt;Mark Robinson&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Mon, 07 Oct 2013 12:11:56 GMT</pubDate></item><item><title>Spinach Thoroughbred</title><link>https://domchristie.co.uk/posts/spinach-thoroughbred/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/spinach-thoroughbred/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/10060185604/&quot; title=&quot;Spinach Thoroughbred by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7356/10060185604_65c7118b44.jpg&quot; alt=&quot;Spinach Thoroughbred&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Thu, 03 Oct 2013 06:41:24 GMT</pubDate></item><item><title>Rick Rubin on Minimalism</title><link>https://domchristie.co.uk/posts/rick-rubin-on-minimalism/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/rick-rubin-on-minimalism/</guid><description>&lt;blockquote&gt;
&lt;p&gt;There’s a tremendous power in using the least amount of information to get a point across.&lt;/p&gt;&lt;cite&gt;“Record Reducer”, Rick Rubin, interviewed &lt;span class=&quot;byline lower&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://www.thedailybeast.com/newsweek/2013/06/26/rick-rubin-on-crashing-kanye-s-album-in-15-days.html&quot;&gt;Newsweek&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Sat, 28 Sep 2013 10:50:19 GMT</pubDate></item><item><title>What am I listening to?</title><link>https://domchristie.co.uk/posts/what-am-i-listening-to/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/what-am-i-listening-to/</guid><description>&lt;p&gt;When I first set up domchristie.co.uk (~2005), I used to update it with what I was reading, watching, taking photos of, and listening to. Given that most the music I listen to is tracked by Last.fm, I thought I’d set up a page that displays this in a nice way.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://scrobbles.domchristie.co.uk/&quot;&gt;Scrobbles&lt;/a&gt; displays the 200 most recently listened to tracks, grouped by album. Click on an album cover to hear the most played track from that album (this can be a bit unpredictable!).&lt;/p&gt;
&lt;p&gt;Scrobbles was built with the Last.fm API and &lt;a href=&quot;http://toma.hk&quot;&gt;Tomahawk&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Fri, 20 Sep 2013 09:52:59 GMT</pubDate></item><item><title>One Six Seven</title><link>https://domchristie.co.uk/posts/one-six-seven/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/one-six-seven/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/9791383644/&quot; title=&quot;One Six Seven by dom christie, on Flickr&quot;&gt;
&lt;img src=&quot;https://farm8.staticflickr.com/7389/9791383644_4d202d7857.jpg&quot; alt=&quot;One Six Seven&quot;&gt;
&lt;/a&gt;&lt;figcaption&gt;Caledonian Road, Islington, 2013&lt;/figcaption&gt;&lt;figure&gt;&lt;/figure&gt;&lt;/figure&gt;</description><pubDate>Tue, 17 Sep 2013 21:51:59 GMT</pubDate></item><item><title>Dieter Rams on good design</title><link>https://domchristie.co.uk/posts/dieter-rams-on-good-design/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/dieter-rams-on-good-design/</guid><description>&lt;blockquote&gt;&lt;p&gt;In my experience, users react very positively when things are clear and understandable… That’s what particularly bothers me today, the arbitrariness and thoughtlessness with which many things are produced and brought to market. Not only in the sector of consumer goods, but also in architecture, in advertising. We have too many unnecessary things everywhere.&lt;/p&gt;
&lt;p&gt;Good design should be innovative. Good design should make a product useful. Good design is aesthetic design. Good design will make a product understandable. Good design is honest. Good design is unobtrusive. Good design is long-lived. Good design is consistent in every detail. Good design is environmentally friendly. Last but not least, good design is as little design as possible&lt;/p&gt;
&lt;cite&gt;Dieter Rams &lt;span class=&quot;lower byline&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://www.youtube.com/watch?v=ahtHKCQUD2k&quot;&gt;Objectified&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Tue, 17 Sep 2013 06:25:15 GMT</pubDate></item><item><title>Backbone.js Patterns Pt.3: Excluding non-persisted attributes</title><link>https://domchristie.co.uk/posts/backbone-js-patterns-pt-3-excluding-non-persisted-attributes/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/backbone-js-patterns-pt-3-excluding-non-persisted-attributes/</guid><description>&lt;p&gt;As I mentioned in &lt;a href=&quot;http://domchristie.co.uk/posts/79&quot;&gt;the previous post&lt;/a&gt;, the &lt;code&gt;toJSON&lt;/code&gt; method is used to customise the data sent to the server.&lt;/p&gt;
&lt;p&gt;Often you’ll have attributes on your model that you don’t want to be persisted e.g. &lt;code&gt;isSelected&lt;/code&gt;. You could customise the &lt;code&gt;toJSON&lt;/code&gt; method on a model-by-model basis, but given that excluding attributes is quite common, we can just include a list of attributes we’d like removed, and modify &lt;code&gt;Backbone.Model.prototype.toJSON&lt;/code&gt;, to handle it.&lt;/p&gt;
&lt;p&gt;First, we’ll add an &lt;code&gt;excludeFromJSON&lt;/code&gt; property to the class definition. This should be an array of attribute keys you&apos;d like to exclude:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  excludeFromJSON: [ &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;isSelected&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then build on our previous &lt;code&gt;toJSON&lt;/code&gt; method to exclude those attributes:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldToJSON &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.toJSON;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;toJSON&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldToJSON.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        excludeFromJSON &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.excludeFromJSON;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(excludeFromJSON) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      _.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;each&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(excludeFromJSON, &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; json[key];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; humps.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;decamelizeKeys&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(json);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;})();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This new &lt;code&gt;Backbone.Model.prototype.toJSON&lt;/code&gt; calls the old method to retrieve a copy of the model&apos;s attributes, then deletes any properties whose keys are in the &lt;code&gt;excludeFromJSON&lt;/code&gt; array. The modified attributes are finally “decamelized”. If you don’t wish to include &lt;a href=&quot;https://github.com/domchristie/humps&quot;&gt;my humps library&lt;/a&gt;, then just &lt;code&gt;return json;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Feedback/questions welcome via &lt;a href=&quot;https://twitter.com/domchristie&quot;&gt;Twitter&lt;/a&gt;, or &lt;a href=&quot;mailto:christiedom@gmail.com&quot;&gt;email&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 12 Sep 2013 07:50:07 GMT</pubDate></item><item><title>Watch</title><link>https://domchristie.co.uk/posts/watch/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/watch/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/9725094637/&quot; title=&quot;Straps &amp;#x26; Batteries by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5531/9725094637_40f38e62c3_c.jpg&quot; alt=&quot;Straps &amp;#x26; Batteries&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Holborn, 2013&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Wed, 11 Sep 2013 21:19:17 GMT</pubDate></item><item><title>Backbone.js Patterns Pt.2: Don’t make me think</title><link>https://domchristie.co.uk/posts/backbone-js-patterns-pt-2-don-t-make-me-think/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/backbone-js-patterns-pt-2-don-t-make-me-think/</guid><description>&lt;p&gt;Different programming languages have different naming conventions. When working with Ruby, for example, it is advised that you separate multi-word variables with underscores. In JavaScript, camelCasing is generally the norm. So when dealing with data that is shared across different environments, you may find yourself having to remember what style to use, e.g. &lt;em&gt;“Was it &lt;code&gt;user.get(&apos;first_name&apos;)&lt;/code&gt;, or &lt;code&gt;user.get(&apos;firstName&apos;)&lt;/code&gt;?”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is where &lt;strong&gt;humps&lt;/strong&gt; is your friend.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/domchristie/humps&quot;&gt;humps&lt;/a&gt; is a small JavaScript library (~100 LoC) that simply converts underscored object keys (and strings) to camelCased, and vice versa (as well as other styles, like PascalCase). By using humps in the &lt;code&gt;toJSON&lt;/code&gt; and &lt;code&gt;parse&lt;/code&gt; methods, we can seamlessly work with the conventions of each language.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;toJSON&lt;/code&gt; and &lt;code&gt;parse&lt;/code&gt; are methods that are typically used to customise the data being sent to and from the server. &lt;code&gt;toJSON&lt;/code&gt; should be used to prepare a model’s attributes for synchronisation &lt;sup&gt;&lt;a href=&quot;#fn79.1&quot; id=&quot;r79.1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;; whereas &lt;code&gt;parse&lt;/code&gt; is typically called when data is sent &lt;em&gt;from&lt;/em&gt; the server, and therefore can be used to prepare a model’s attributes before they are set on the model itself.&lt;/p&gt;
&lt;p&gt;Starting with the &lt;code&gt;parse&lt;/code&gt; method, overwrite &lt;code&gt;Backbone.Model.prototype.parse&lt;/code&gt;, passing the results of the old `parse` method into &lt;code&gt;humps.camelizeKeys&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldParse &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.parse;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; parsed &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldParse.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; humps.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;camelizeKeys&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(parsed);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;})();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now, the following JSON:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;first_name&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Jon&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;last_name&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Snow&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;is_steward&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;will be converted to camelCase and will be accessible on the model as follows:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// assuming user is an instance of a Backbone model&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;user.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;firstName&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// &quot;Jon&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;user.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;lastName&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// &quot;Snow&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;user.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;isSteward&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember, that &lt;code&gt;parse&lt;/code&gt; is only called when a model’s is updated via a &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;save&lt;/code&gt;. If you are populating a model’s attributes manually, you’ll need to pass in &lt;code&gt;{ parse: true }&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;first_name&quot;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&quot;Jon&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}, { parse: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’ll also work with nested objects.&lt;/p&gt;
&lt;p&gt;The same pattern can be applied to &lt;code&gt;toJSON&lt;/code&gt;, which will convert camelCased object keys (back) to underscored:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldToJSON &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.toJSON;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;toJSON&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldToJSON.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; humps.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;decamelizeKeys&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(json);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;})();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Feedback welcome via &lt;a href=&quot;https://twitter.com/domchristie&quot;&gt;Twitter&lt;/a&gt;, or &lt;a href=&quot;mailto:christiedom@gmail.com&quot;&gt;email&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Part 3 in this miniseries will extend the &lt;code&gt;toJSON&lt;/code&gt; method to exclude non-persisted attributes from its output.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
  &lt;p id=&quot;fn79.1&quot;&gt;&lt;a href=&quot;#r79.1&quot;&gt;[1]&lt;/a&gt; The Backbone.js documentation for &lt;code&gt;toJSON&lt;/code&gt; previously suggested that it could be used to clone a model’s attributes for use in a template, as well as for persistence. Following a &lt;a href=&quot;https://github.com/jashkenas/backbone/issues/2134&quot;&gt;discussion on the purpose of &lt;code&gt;toJSON&lt;/code&gt;&lt;/a&gt;, it was decided that this “double duty” should be simplified. It is now not recommended for preparing a model for rendering.&lt;/p&gt;
&lt;/section&gt;</description><pubDate>Thu, 29 Aug 2013 08:29:51 GMT</pubDate></item><item><title>Backbone.js Patterns Pt.1: Maintaining the Uniform Access Principle</title><link>https://domchristie.co.uk/posts/backbone-js-patterns-pt-1-maintaining-the-uniform-access-principle/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/backbone-js-patterns-pt-1-maintaining-the-uniform-access-principle/</guid><description>&lt;blockquote&gt;The entire [Backbone.js] source is annotated with the explicit idea that you should be feeling free, if something is not working, to dig in and figure out how it works and also to dig in and overwrite things if you find the need. &lt;cite&gt;Jeremy Ashkenas &lt;span class=&quot;lower byline&quot;&gt;on&lt;/span&gt; &lt;a href=&quot;http://javascriptjabber.com/004-jsj-backbone-js-with-jeremy-ashkenas/&quot;&gt;JavaScript Jabber 004&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;I thought I&apos;d share a few patches that I&apos;ve found useful when developing web apps with Backbone.js. The techniques overwrite prototype methods, but in a responsible way that keeps default behaviours unchanged.&lt;/p&gt;
&lt;p&gt;This part takes pointers from &lt;a href=&quot;http://stackoverflow.com/questions/6695503/whats-the-best-way-to-override-model-getattr-in-backbone-js&quot;&gt;this Stack Overflow question&lt;/a&gt; and the &lt;a href=&quot;http://c2.com/cgi/wiki?UniformAccessPrinciple&quot;&gt;Uniform Access Principle&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation&lt;/p&gt;&lt;cite&gt;Bertrand Meyer&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Lets say you have a user model as follows:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;App &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;App.User &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  defaults: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    firstName: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;Jon&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    lastName: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;Snow&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fullName&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;firstName&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;lastName&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; App.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fullName&lt;/code&gt; &lt;em&gt;could&lt;/em&gt; be accessed by calling &lt;code&gt;user.fullName()&lt;/code&gt;, but that would be inconsistent with accessing other attributes. What’s more, if, for example, we decided to compute &lt;code&gt;fullName&lt;/code&gt; on the server, we&apos;d have to replace all occurrences of &lt;code&gt;user.fullName()&lt;/code&gt; with &lt;code&gt;user.get(&apos;fullName&apos;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It would be better to access &lt;code&gt;fullName&lt;/code&gt; (and any &lt;em&gt;attribute-like&lt;/em&gt; method) via &lt;code&gt;user.get(&apos;fullName&apos;)&lt;/code&gt;. This can be achieved by overwriting &lt;code&gt;Backbone.Model.prototype.get&lt;/code&gt;:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldGet &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.get;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;attr&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;[attr] &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;function&apos;&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;[attr]();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; oldGet.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;})();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This stores the original &lt;code&gt;get&lt;/code&gt; method in &lt;code&gt;oldGet&lt;/code&gt;, calls the requested method if it exists on the model, or calls the original &lt;code&gt;get&lt;/code&gt; method if it doesn&apos;t.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Backbone.Model.prototype.escape&lt;/code&gt; retrieves attributes by making a call to &lt;code&gt;Backbone.Model.prototype.get&lt;/code&gt;, and so should also work with this technique.&lt;/p&gt;
&lt;p&gt;Related: &lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties/&quot;&gt;computed properties in Ember.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Feedback welcome via &lt;a href=&quot;https://twitter.com/domchristie&quot;&gt;Twitter&lt;/a&gt;, or &lt;a href=&quot;mailto:christiedom@gmail.com&quot;&gt;email&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;Part 2 will look at techniques for customising &lt;code&gt;toJSON&lt;/code&gt; and &lt;code&gt;parse&lt;/code&gt; for synchronising data with the server.&lt;/p&gt;</description><pubDate>Wed, 21 Aug 2013 09:11:25 GMT</pubDate></item><item><title>Improving TfL’s Live Bus Timetables: Uncle Gus</title><link>https://domchristie.co.uk/posts/improving-tfl-s-live-bus-timetables-uncle-gus/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/improving-tfl-s-live-bus-timetables-uncle-gus/</guid><description>&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; I&apos;ve created a simple London bus timetable web app: &lt;a href=&quot;http://unclegus.net?link=tldr&quot;&gt;Uncle Gus&lt;/a&gt; (requires a &lt;a href=&quot;http://zeptojs.com/#platforms&quot;&gt;reasonably modern browser&lt;/a&gt; e.g. Safari, Chrome, Firefox).&lt;/p&gt;
&lt;p&gt;If you have ever used any of TfL’s live bus displays, you&apos;ll have probably seen one in a state that offers very little, if any, relevant information about the bus you hope to catch.&lt;/p&gt;
&lt;p&gt;The current displays page-through imminent arrivals about every 10 seconds, four buses at a time. The most imminent bus (from any route) is always displayed at the top. This seems pretty logical, until you start using them …&lt;/p&gt;
&lt;img src=&quot;https://domchristie.s3.amazonaws.com/uncle-gus-before.png&quot; alt=&quot;&quot; title=&quot;&quot;&gt;
&lt;p style=&quot;margin-top: -1em;&quot;&gt;&lt;small&gt;&lt;strong&gt;Above:&lt;/strong&gt; an example TfL live bus timetable (without pagination).&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;If you want to know when your next bus is going to arrive, it has to either be the most imminent arrival, or the display has to be showing the first page of results &lt;em&gt;and&lt;/em&gt; your bus has to be in the top four arrivals. Unfortunately this is rarely the case, so you end staring at the display, waiting for that first page to come around, making sure to keep track of your bus&apos;s earliest arrival in case it’s not on the first page. (More often than not, I end up getting bored, look away, and miss that all-important first page!)&lt;/p&gt;
&lt;p&gt;So I started thinking about how these displays could be improved. The result is &lt;a href=&quot;http://unclegus.net&quot;&gt;Uncle Gus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For a given stop, it formats each route on a single row, accompanied with the next 3 arrivals. It removes the (now unnecessary) order number and shortens “min” to just “m”. So the same data as above could be displayed as:&lt;/p&gt;
&lt;img src=&quot;https://domchristie.s3.amazonaws.com/uncle-gus-after.png&quot; alt=&quot;&quot; title=&quot;&quot;&gt;
&lt;p&gt;Ah, that’s better. &lt;a href=&quot;http://unclegus.net?link=try&quot;&gt;Give it a try!&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 09 Aug 2013 12:24:31 GMT</pubDate></item><item><title>Compair: a typeface comparison tool</title><link>https://domchristie.co.uk/posts/compair-a-typeface-comparison-tool/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/compair-a-typeface-comparison-tool/</guid><description>&lt;p&gt;&lt;a title=&quot;Try out Compair&quot; href=&quot;http://compaired.herokuapp.com/&quot;&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/compair.png&quot; alt=&quot;Screenshot of Compair: a tool for comparing typefaces&quot; title=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;http://www.fivesimplesteps.com/products/combining-typefaces&quot;&gt;Combining Typefaces&lt;/a&gt;, Tim Brown outlines a process for choosing complementary typefaces. Part of this process includes comparing text set in different faces, both at macro level (to gauge characteristics such as texture and contrast), and at micro level (to examine the compatibility of the finer details).&lt;/p&gt;
&lt;p&gt;To make comparisons easier at micro level, I created a basic online tool, &lt;a href=&quot;http://compaired.herokuapp.com/&quot;&gt;Compair&lt;/a&gt;. Simply choose 2 fonts, some sample text, and compare features side-by-side such as x-height, cap-height, and character width.&lt;/p&gt;
&lt;p&gt;At the moment, it’s pretty basic, but I’m hoping to add more kinds of micro comparisons (e.g. overlay the two faces), add macro comparisons, and perhaps integrate with the Google Fonts API.&lt;/p&gt;
&lt;p&gt;Related: &lt;a href=&quot;http://jessicahische.is/talkingtype&quot;&gt;Upping Your Type Game &lt;span class=&quot;byline&quot;&gt;by&lt;/span&gt; Jessica Hische&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Sun, 28 Jul 2013 21:14:23 GMT</pubDate></item><item><title>Designers Humanize Technology</title><link>https://domchristie.co.uk/posts/designers-humanize-technology/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/designers-humanize-technology/</guid><description>&lt;blockquote&gt;&lt;p&gt;Simply, designers humanize technology. Designers are trained to embrace chaos and complexity, to hold multiple and often competing ideas in their heads at one time, to be flexible and nimble in the face of changing constraints, and most importantly, to visualize concepts, systems and services that don&apos;t yet exist. Designers tell stories about how the future ought to be.&lt;/p&gt;&lt;cite&gt;Jon Kolko &lt;span class=&quot;lower byline&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://www.huffingtonpost.com/jon-kolko/design-liberal-art_b_2427295.html&quot;&gt;Now Hiring: The Most Liberal Art&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Sun, 21 Jul 2013 20:38:44 GMT</pubDate></item><item><title>Making use of new design technologies</title><link>https://domchristie.co.uk/posts/making-use-of-new-design-technologies/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/making-use-of-new-design-technologies/</guid><description>&lt;blockquote&gt;&lt;p&gt;Occasionally designers seem to seek credit merely for possessing a new technology, rather than using it to make better designs. Computers and their affiliated apparatus can do powerful things graphically, in part by turning out the hundreds of plots necessary for good data analysis. But at least a few computer graphics only evoke the response “Isn’t it remarkable that the computer can be programmed to draw like that?” instead of “My, what interesting data.”&lt;/p&gt;&lt;cite&gt;Edward Tufte &lt;span class=&quot;lower byline&quot;&gt;in&lt;/span&gt; The Visual Display of Quantitative Data&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Wed, 03 Jul 2013 07:04:33 GMT</pubDate></item><item><title>Untrustworthy Fast News</title><link>https://domchristie.co.uk/posts/untrustworthy-fast-news/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/untrustworthy-fast-news/</guid><description>&lt;p&gt;Timeless words from a 19th century journalist on the use of the electrical telegraph:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Intelligence, thus hastily gathered and transmitted, has also its drawbacks, and is not so trustworthy as the news which starts later and travels slower.&lt;/p&gt;
&lt;cite&gt;&lt;span class=&quot;lower byline&quot;&gt;Taken from&lt;/span&gt; The Information &lt;span class=&quot;lower byline&quot;&gt;by&lt;/span&gt; James Gleick&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Tue, 02 Jul 2013 05:57:56 GMT</pubDate></item><item><title>Wing</title><link>https://domchristie.co.uk/posts/wing/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/wing/</guid><description>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/9174909387/&quot; title=&quot;wing by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5539/9174909387_49ea552084.jpg&quot; alt=&quot;wing&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 2007&lt;/p&gt;</description><pubDate>Sun, 30 Jun 2013 16:50:02 GMT</pubDate></item><item><title>Korg Volca Series</title><link>https://domchristie.co.uk/posts/korg-volca-series/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/korg-volca-series/</guid><description>&lt;img src=&quot;https://domchristie.s3.amazonaws.com/korg-volca.jpg&quot; alt=&quot;Korg Volca Synthesizers&quot;&gt;
&lt;p&gt;Pre-ordered. &lt;a href=&quot;http://www.youtube.com/watch?v=_Gau7UIzYY0&quot;&gt;See demo video&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Mon, 17 Jun 2013 11:27:21 GMT</pubDate></item><item><title>Albums Mid-2013</title><link>https://domchristie.co.uk/posts/albums-mid-2013/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/albums-mid-2013/</guid><description>&lt;p&gt;Currently listening to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Ghostpoet&lt;/strong&gt;—Some Say I So I Say Light&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bibio&lt;/strong&gt;—Silver Wilkinson&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bonobo&lt;/strong&gt;—The North Borders&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Jon Hopkins&lt;/strong&gt;—Immunity&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Boards of Canada&lt;/strong&gt;—Tomorrow&apos;s Harvest&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Gold Panda&lt;/strong&gt;—Half of Where You Live&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also looking forward to checking out the new &lt;strong&gt;Mount Kimbie&lt;/strong&gt; album, as well as new records from &lt;strong&gt;Tunng&lt;/strong&gt; and &lt;strong&gt;Holden&lt;/strong&gt; (both released next week).&lt;/p&gt;</description><pubDate>Thu, 13 Jun 2013 14:25:00 GMT</pubDate></item><item><title>Daughter</title><link>https://domchristie.co.uk/posts/daughter/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/daughter/</guid><description>&lt;p&gt;I’ve been listening to Daughter a lot recently. The song-writing and production on The Wild Youth EP, is incredible. Youth is outstanding.&lt;/p&gt;
&lt;iframe src=&quot;https://embed.spotify.com/?uri=spotify:album:5VFxl0Fddo5wlShNHeyGCL&quot; width=&quot;300&quot; height=&quot;380&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot;&gt;&lt;/iframe&gt;</description><pubDate>Sun, 28 Apr 2013 10:20:00 GMT</pubDate></item><item><title>What makes us feel good about our work?</title><link>https://domchristie.co.uk/posts/what-makes-us-feel-good-about-our-work/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/what-makes-us-feel-good-about-our-work/</guid><description>&lt;p&gt;Interesting &lt;a href=&quot;http://www.ted.com/talks/dan_ariely_what_makes_us_feel_good_about_our_work.html&quot;&gt;TED talk from Dan Ariely&lt;/a&gt;, backed with some intriguing experiments. His book, &lt;a href=&quot;http://www.amazon.co.uk/Predictably-Irrational-Hidden-Forces-Decisions/dp/0007256531/ref=sr_1_1?ie=UTF8&amp;#x26;qid=1366366008&amp;#x26;sr=8-1&amp;#x26;keywords=predictably+irrational&quot;&gt;Predictably Irrational&lt;/a&gt;, is well worth reading.&lt;/p&gt;
&lt;iframe src=&quot;https://embed.ted.com/talks/dan_ariely_what_makes_us_feel_good_about_our_work.html&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 19 Apr 2013 09:14:29 GMT</pubDate></item><item><title>Vox Populi</title><link>https://domchristie.co.uk/posts/vox-populi/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/vox-populi/</guid><description>&lt;p&gt;BBC London recently reported that Transport for London may soon disallow cash fares on London buses. For the obligatory vox pops section of the report, the BBC appeared to be in Croydon, asking punters what they thought. In typical fashion, the producers/editors picked these &lt;em&gt;insightful&lt;/em&gt; words from one commuter:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;It’s not really good news for people who want to pay by cash&lt;/p&gt;&lt;cite&gt;&lt;a href=&quot;http://www.bbc.co.uk/news/uk-england-london-22146675&quot;&gt;Are London buses set to be cashless?&lt;/a&gt; &lt;span class=&quot;lower byline&quot;&gt;at&lt;/span&gt; ~00.25&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;This instantly made me think of Charlie Brooker’s &lt;a href=&quot;http://www.youtube.com/watch?v=aHun58mz3vI&quot;&gt;How to Report the News&lt;/a&gt;, and gave me a great excuse to post it below:&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/aHun58mz3vI?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Wed, 17 Apr 2013 12:19:00 GMT</pubDate></item><item><title>Overload, clutter, and confusion</title><link>https://domchristie.co.uk/posts/overload-clutter-and-confusion/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/overload-clutter-and-confusion/</guid><description>&lt;blockquote&gt;&lt;p&gt;Overload, clutter, and confusion are not attributes of information, they are failures of design. So if something is cluttered, fix your design, don&apos;t throw out information. If something is confusing, don&apos;t blame your victim—the audience—instead, fix the design. And if the numbers are boring, get better numbers&lt;/p&gt;&lt;cite&gt;Edward Tufte &lt;span class=&quot;lower byline&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://adage.com/article/adagestat/edward-tufte-adagestat-q-a/230884/&quot;&gt;The AdAgeStat Q&amp;#x26;A&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Tue, 16 Apr 2013 16:48:48 GMT</pubDate></item><item><title>Cennydd Bowles: The Things of the Future</title><link>https://domchristie.co.uk/posts/cennydd-bowles-the-things-of-the-future/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/cennydd-bowles-the-things-of-the-future/</guid><description>&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/-3nuAjlgu1o?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 12 Apr 2013 08:45:00 GMT</pubDate></item><item><title>Inge Druckrey on Roman Lettering</title><link>https://domchristie.co.uk/posts/inge-druckrey-on-roman-lettering/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/inge-druckrey-on-roman-lettering/</guid><description>&lt;blockquote&gt;
  &lt;p&gt;The structure of the roman capital letter is simple, and beautiful. It uses clear geometric elements: the half-circle, vertical, diagonal, horizontal. It is based on a grid of square, half-square, quarter-square … it’s like a continuous rhythm of very simple form elements, and &lt;em&gt;that&lt;/em&gt; gives the coherence.&lt;/p&gt;
&lt;cite&gt;Inge Druckrey &lt;span class=&quot;lower byline&quot;&gt;in&lt;/span&gt; &lt;a href=&quot;http://vimeo.com/45232468&quot;&gt;Teaching to See&lt;/a&gt; at &lt;a href=&quot;http://vimeo.com/45232468#t=744&quot;&gt;12:25&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/45232468?title=0&amp;#x26;byline=0&amp;#x26;portrait=0&amp;#x26;color=ffffff&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Sun, 07 Apr 2013 19:36:01 GMT</pubDate></item><item><title>Blue</title><link>https://domchristie.co.uk/posts/blue/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/blue/</guid><description>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8628185921/&quot; title=&quot;Blue by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8265/8628185921_66fdb33b2c.jpg&quot; alt=&quot;Blue&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gospel Oak, London:&lt;/p&gt;
&lt;a href=&quot;http://goo.gl/maps/2dYQF&quot;&gt;
&lt;img src=&quot;https://domchristie.s3.amazonaws.com/gospel.jpg&quot; alt=&quot;Google Street View of Gospel Oak&quot;&gt;&lt;/a&gt;
&lt;p&gt;Related: &lt;a href=&quot;http://www.bbc.co.uk/programmes/p00wskdk&quot;&gt;A History of Art in Three Colours: Blue&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sun, 07 Apr 2013 19:08:09 GMT</pubDate></item><item><title>TL;DR</title><link>https://domchristie.co.uk/posts/tl-dr/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tl-dr/</guid><description>&lt;blockquote&gt;&lt;p&gt;I realize that we live in a TL;DR culture … But it&apos;s really not ok to act functionally illiterate when you&apos;re not actually illiterate, when an advanced society that once put a man on the moon worked so hard to educate you.&lt;/p&gt;
&lt;cite&gt;&lt;a href=&quot;http://hackingdistributed.com/2013/01/29/mongo-ft/#not-a-tl-dr&quot;&gt;Emin Gün Sirer&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Related and well worth a read: &lt;a href=&quot;http://hackingdistributed.com/2013/03/26/summly/&quot;&gt;What&apos;s Actually Wrong with Yahoo&apos;s Purchase of Summly&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 27 Mar 2013 13:34:33 GMT</pubDate></item><item><title>Hierarchy</title><link>https://domchristie.co.uk/posts/hierarchy/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/hierarchy/</guid><description>&lt;blockquote&gt;&lt;p&gt;The Feynman lectures (3 volumes) write about all of physics in 1800 pages, using only 2 levels of hierarchical headings: chapters and A-level heads in the text. It also uses the methodology of &lt;em&gt;sentences&lt;/em&gt; which then cumulate sequentially into &lt;em&gt;paragraphs&lt;/em&gt;, rather than the grunts of bullet points. Undergraduate Caltech physics is very complicated material, but it didn&apos;t require an elaborate hierarchy to organize. A useful decision rule in thinking and showing is &quot;What would Feynman do?&quot;&lt;/p&gt;&lt;cite&gt;&lt;a href=&quot;http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0000hB&quot;&gt;Edward Tufte&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Fri, 22 Mar 2013 16:23:57 GMT</pubDate></item><item><title>Camille—Ta Douleur</title><link>https://domchristie.co.uk/posts/camille-ta-douleur/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/camille-ta-douleur/</guid><description>&lt;iframe style=&quot;--width: 500; --height: 375&quot; src=&quot;https://www.youtube-nocookie.com/embed/V7ryxk41HtI?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Mon, 18 Mar 2013 23:11:23 GMT</pubDate></item><item><title>Rollers</title><link>https://domchristie.co.uk/posts/rollers/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/rollers/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8557454132/&quot; title=&quot;Rollers by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8389/8557454132_8bded2856a.jpg&quot; alt=&quot;Paint Rollers&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Thu, 14 Mar 2013 13:20:39 GMT</pubDate></item><item><title>sound 323</title><link>https://domchristie.co.uk/posts/sound-323/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/sound-323/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8556332547/&quot; title=&quot;CNV00037 by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8110/8556332547_7d48cef917.jpg&quot; alt=&quot;sound 323 shop front&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;Old record store. Unfortunately closed before I moved to Highgate.&lt;/p&gt;</description><pubDate>Thu, 14 Mar 2013 13:18:14 GMT</pubDate></item><item><title>Post 57</title><link>https://domchristie.co.uk/posts/post-57/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/post-57/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I photograph to see what the world looks like in photographs.&lt;/p&gt;
&lt;cite&gt;Garry Winogrand&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/3235927671/&quot; title=&quot;yellow slide by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3131/3235927671_3919c607ae.jpg&quot; alt=&quot;yellow slide&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Wed, 06 Mar 2013 09:38:05 GMT</pubDate></item><item><title>Twitter Burnout</title><link>https://domchristie.co.uk/posts/twitter-burnout/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/twitter-burnout/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I find that my burnout is correlative to the amount of time I spend on Twitter.&lt;/p&gt;
&lt;cite&gt;AJ O’Neal on &lt;a href=&quot;http://javascriptjabber.com/046-jsj-staying-current/&quot;&gt;JSJ: Staying Current&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Wed, 20 Feb 2013 10:11:57 GMT</pubDate></item><item><title>Guggenheim</title><link>https://domchristie.co.uk/posts/guggenheim/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/guggenheim/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8489402516/&quot; title=&quot;guggenheim by dom christie, on Flickr&quot;&gt;&lt;img width=&quot;896&quot; height=&quot;611&quot; src=&quot;https://live.staticflickr.com/8370/8489402516_f290e20295_b.jpg&quot; alt=&quot;guggenheim&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;2010&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Tue, 19 Feb 2013 14:07:05 GMT</pubDate></item><item><title>Complexity</title><link>https://domchristie.co.uk/posts/complexity/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/complexity/</guid><description>&lt;blockquote&gt;It&apos;s better to hide [complexity] from people, than to force them to learn about it and deal with it. &lt;cite&gt;Tom Dale on &lt;a href=&quot;http://javascriptjabber.com/047-jsj-specialized-vs-monolithic-with-james-halliday-and-tom-dale/&quot;&gt;JSJ: Specialized vs Monolithic&lt;/a&gt; (at around 18:20)&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Mon, 18 Feb 2013 20:39:37 GMT</pubDate></item><item><title>Dan Deacon—True Thrush</title><link>https://domchristie.co.uk/posts/dan-deacon-true-thrush/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/dan-deacon-true-thrush/</guid><description>&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/XnXiXlF7olo?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Thu, 14 Feb 2013 20:21:19 GMT</pubDate></item><item><title>Playlist: Jan 2013</title><link>https://domchristie.co.uk/posts/playlist-jan-2013/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/playlist-jan-2013/</guid><description>&lt;p&gt;Discovered &lt;a href=&quot;http://www.erasedtapes.com/&quot;&gt;Erased Tapes&lt;/a&gt; this month, and in particular, &lt;strong&gt;Nils Frahm&lt;/strong&gt;. &lt;a href=&quot;https://soundcloud.com/four-tet/0181-1&quot;&gt;Four Tet&apos;s latest release, 0181&lt;/a&gt; is lovely, and his &lt;a href=&quot;https://soundcloud.com/four-tet/return-to-plastic-people-september-2010-aka-fact-mix-182&quot;&gt;Return to Plastic People mix&lt;/a&gt; is superb: Rocketnumbernine – Matthew and Toby (Four Tet remix) and J&amp;#x26;W Beat by Floating Points are highlights.&lt;/p&gt;
&lt;iframe src=&quot;https://embed.spotify.com/?uri=spotify:user:bonanza9:playlist:2eLyQUQ6fmh7BFjOv5leX6&quot; width=&quot;300&quot; height=&quot;380&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot;&gt;&lt;/iframe&gt;</description><pubDate>Thu, 07 Feb 2013 22:50:31 GMT</pubDate></item><item><title>Foliage</title><link>https://domchristie.co.uk/posts/foliage/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/foliage/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8444815000/&quot; title=&quot;Foliage by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8332/8444815000_2cfc447a1a.jpg&quot; alt=&quot;Foliage&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;2001/02&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Mon, 04 Feb 2013 13:25:33 GMT</pubDate></item><item><title>2CV</title><link>https://domchristie.co.uk/posts/2cv/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/2cv/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8441923921/&quot; title=&quot;2CV by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8378/8441923921_e747052631.jpg&quot; alt=&quot;2CV&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;Port Isaac, 2010&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Sun, 03 Feb 2013 22:30:23 GMT</pubDate></item><item><title>Etna</title><link>https://domchristie.co.uk/posts/etna/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/etna/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8434295523/&quot; title=&quot;Etna by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8325/8434295523_90e9cac9b0.jpg&quot; alt=&quot;Etna&quot;&gt;&lt;/a&gt;&lt;figcaption&gt;2011 (not the summit, but close enough).&lt;/figcaption&gt;&lt;/figure&gt;</description><pubDate>Fri, 01 Feb 2013 11:17:29 GMT</pubDate></item><item><title>The Awkwardness of Drag and Drop File Uploads</title><link>https://domchristie.co.uk/posts/the-awkwardness-of-drag-and-drop-file-uploads/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-awkwardness-of-drag-and-drop-file-uploads/</guid><description>&lt;p&gt;Steps for drag and drop file upload:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Switch from web browser to file browser e.g. Finder or Windows Explorer&lt;/li&gt;
&lt;li&gt;Navigate to files&lt;/li&gt;
&lt;li&gt;Arrange windows so that files can be dragged to web browser (resize/move/switch windows to ensure droppable area is visible)&lt;/li&gt;
&lt;li&gt;Drag and drop files to droppable area&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Compared with uploading via basic &lt;code&gt;input[type=file]&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open file browser from web browser&lt;/li&gt;
&lt;li&gt;Navigate to files&lt;/li&gt;
&lt;li&gt;Choose files to upload&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Related: &lt;a href=&quot;http://thenextweb.com/dd/2012/09/03/user-experience-trends-problem-stealing-bad-ideas/&quot;&gt;User experience trends and the problem with stealing bad ideas&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Tue, 29 Jan 2013 13:48:54 GMT</pubDate></item><item><title>Man Power (rgb)</title><link>https://domchristie.co.uk/posts/man-power-rgb/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/man-power-rgb/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8425976699/&quot; title=&quot;Man Power (rgb) by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8235/8425976699_68a6c667fc.jpg&quot; alt=&quot;Man Power (rgb)&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Tue, 29 Jan 2013 13:16:51 GMT</pubDate></item><item><title>Features of Print Media (from a digital media perspective)</title><link>https://domchristie.co.uk/posts/features-of-print-media-from-a-digital-media-perspective/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/features-of-print-media-from-a-digital-media-perspective/</guid><description>&lt;p&gt;This rather amusing list of print media features comes from Andrew Betts&apos; talk, &lt;a href=&quot;http://2012.full-frontal.org/#andrew&quot;&gt;Offline Rules&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Works offline&lt;/li&gt;
&lt;li&gt;Portable&lt;/li&gt;
&lt;li&gt;Long battery life&lt;/li&gt;
&lt;li&gt;Can be read in bright sunlight&lt;/li&gt;
&lt;li&gt;Cheap&lt;/li&gt;
&lt;li&gt;Ubiquity&lt;/li&gt;
&lt;li&gt;Bookmarking&lt;/li&gt;
&lt;li&gt;Sharing&lt;/li&gt;
&lt;li&gt;Fast start up&lt;/li&gt;
&lt;li&gt;Clipping/saving&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Mon, 14 Jan 2013 07:55:07 GMT</pubDate></item><item><title>See Attached</title><link>https://domchristie.co.uk/posts/see-attached/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/see-attached/</guid><description>&lt;div&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/see-attached-crop.png&quot;&gt;&lt;/div&gt;
&lt;p&gt;I can&apos;t tell you how many times I&apos;ve mistakenly sent an email before adding the attachments; so I was pleased to see this pop up (apparently this was previously a Gmail labs feature). However, as &lt;a href=&quot;https://twitter.com/auxilit&quot;&gt;a colleague&lt;/a&gt; pointed out, wouldn&apos;t it be nice if the message accompanied a file browser (rather than just a confirm dialog)?&lt;/p&gt;</description><pubDate>Sun, 13 Jan 2013 15:29:52 GMT</pubDate></item><item><title>Launderette</title><link>https://domchristie.co.uk/posts/launderette/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/launderette/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/8370419450/&quot; title=&quot;launderette by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8325/8370419450_bc21c896e0.jpg&quot; alt=&quot;Washing machine drum with tobacco inside&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Fri, 11 Jan 2013 12:16:42 GMT</pubDate></item><item><title>A Starting Point for Choosing Typefaces</title><link>https://domchristie.co.uk/posts/a-starting-point-for-choosing-typefaces/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/a-starting-point-for-choosing-typefaces/</guid><description>&lt;p&gt;This is a brief follow up to something I mentioned in &lt;a href=&quot;http://domchristie.co.uk/posts/42&quot;&gt;my previous post about Helvetica&lt;/a&gt; (and the film). I wrote that choosing a typefaces requires careful consideration. Aral Balkan&apos;s recent article &lt;a href=&quot;http://aralbalkan.com/notes/design-is-not-veneer/&quot;&gt;Design is not veneer&lt;/a&gt; expresses this perfectly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At the very least, you should be asking ‘why?’ Why this font? What is the feeling I’m trying to convey? Is this text meant to be serious, fun, exciting, solemn, scary? What’s the voice I’m trying to achieve? And for whom? Who is my audience? Whom am I designing for?&lt;/p&gt;
&lt;cite&gt;Aral Balkan&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Fri, 11 Jan 2013 11:47:28 GMT</pubDate></item><item><title>Helvetica (2007)</title><link>https://domchristie.co.uk/posts/helvetica-2007/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/helvetica-2007/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/2635620085/&quot; title=&quot;ringlikon by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3022/2635620085_8cfba0e62f.jpg&quot; alt=&quot;ringlikon&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;I finally got round to watching &lt;a href=&quot;http://www.imdb.com/title/tt0847817/&quot;&gt;Helvetica&lt;/a&gt;, a film that documents various designers&apos; thoughts on the typeface, along with a bit of history surrounding modern design.&lt;/p&gt;
&lt;p&gt;Towards the beginning of the film I was quite surprised by some of the designers&apos; feelings towards typography, and the way they advocate Helvetica&apos;s use:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[Helvetica] was doing away with manual details. We were impressed by that, because it was more neutral, and neutralism was a word that we loved. [Type] should be neutral. It shouldn&apos;t have a meaning in itself. The meaning is in the content of the text, not in the typeface. That&apos;s why we loved Helvetica very much.&lt;/p&gt;
&lt;cite&gt;Wim Crouwel&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;p&gt;Massimo Vignelli worked on the American Airlines branding, and the signage of the New York subway:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are people that think that type should be expressive … I don&apos;t think type should be expressive at all. I can write the word dog with any typeface and it doesn&apos;t have to look like a dog, but there are people that when they write dog it should bark!&lt;/p&gt;
&lt;p&gt;It is a modern type. It is a very clear type. It&apos;s good for everything, pretty much.&lt;/p&gt;
&lt;p&gt;You can say ‘I love you’ in Helvetica. You can say it with Helvetica Extra Light, if you want to be really fancy. You can say it with the Extra Bold if it&apos;s really intense and passionate, and it might work!&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Massimo Vignelli&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I feel that every typeface always expresses some meaning however it is used, and that choosing typefaces requires careful consideration. After all, all typefaces have been created by someone and for some reason, and many have a deep history behind them, which is partly the reason why ‘Keep Calm and Carry On’ set in Helvetica (below right) just looks wrong (to my eyes, at least). Helvetica is a hugely versatile typeface and can be very expressive as Vignelli explains(!), but I don&apos;t feel it is right for everything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Below:&lt;/strong&gt; For want of a better example: ‘Keep Calm and Carry On’ set in Gill Sans (left) and Helvetica (right). Neither use the typeface of &lt;a href=&quot;http://wartimeposters.co.uk/&quot;&gt;the original&lt;/a&gt;.&lt;/p&gt;
&lt;img src=&quot;https://domchristie.s3.amazonaws.com/keep-calm-gill-helvetica.gif&quot; alt=&quot;Keep Calm and Carry On comparison between Gill Sans and Helvetica&quot;&gt;
&lt;p&gt;The film moves on to examine the use of type in post-modern design, grunge, and rebellion against using Helvetica without question, which includes this great piece from David Carson:&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 375&quot; src=&quot;https://www.youtube-nocookie.com/embed/hpIv7ww78zM?rel=0&amp;#x26;showinfo=0#t=131s&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;The film then settles on interviews with younger designers and their opinions on working with Helvetica today.&lt;/p&gt;
&lt;p&gt;For me, Helvetica is a great typeface and is fit for many applications: I&apos;ve often fallen into the trap of trying to find something similar to Helvetica for the sake of not using Helvetica, when Helvetica has been perfectly suitable all along. As a web designer, typeface choices are beginning to open up with the availability of web fonts, but their use can be a performance concern:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p&gt;Hey everyone, can you please stop with web fonts on mobile experiences? I&apos;m tired of seeing a blank page for the first 5 seconds.&lt;/p&gt;— Nicholas C. Zakas (@slicknet) &lt;a href=&quot;https://twitter.com/slicknet/status/191213660511813632&quot; data-datetime=&quot;2012-04-14T17:17:43+00:00&quot;&gt;April 14, 2012&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;… which makes the choice even harder.&lt;/p&gt;</description><pubDate>Fri, 04 Jan 2013 14:51:36 GMT</pubDate></item><item><title>Careful Design</title><link>https://domchristie.co.uk/posts/careful-design/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/careful-design/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Sometimes we want to capture people’s attention at a glance to communicate something fast. At other times we want to have the interface fade away into the background, letting people paint pictures in their minds with our words…&lt;/p&gt;
&lt;p&gt;I tend to distinguish between these two broad objectives as designing for impact on the one hand, and designing for immersion on the other. What defines them is interruption. Impact needs an attention-grabbing interruption. Immersion requires us to remove interruption from the interface. Careful design &lt;em&gt;deliberately&lt;/em&gt; interrupts but doesn’t &lt;em&gt;accidentally&lt;/em&gt; disrupt.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Jon Tan in &lt;a href=&quot;http://24ways.org/2012/science/&quot;&gt;Science!&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description><pubDate>Wed, 02 Jan 2013 14:07:26 GMT</pubDate></item><item><title>People Quickly Expect &quot;App&quot;</title><link>https://domchristie.co.uk/posts/people-quickly-expect-app/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/people-quickly-expect-app/</guid><description>&lt;p&gt;I&apos;m a big fan of what Yehuda Katz and Tom Dale are doing in their approach to creating &lt;a href=&quot;http://emberjs.com/&quot;&gt;ember.js&lt;/a&gt; (formely SproutCore 2.0). The background to this approach is discussed in Yehuda&apos;s TXJS 2011 talk (below), which is well worth a watch.&lt;/p&gt;
&lt;p&gt;In addition to arguing the case for going beyond microframeworks, Yehuda also talks about native vs. web UI design:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;People quickly expect &quot;application&quot; when you start adding features like transitions … When you build a UI for the web, you need to either make it very distinctively different from [native] applications: make it very much feel like the web; or you need to get it right. If you get it half way, it feels wrong. If you don&apos;t want to go the whole way, don&apos;t do transitions at all.&lt;/p&gt;
  &lt;cite&gt;Yehuda Katz in his TXJS 2011 talk (below) at ~32:30&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&apos;s fascinating that people&apos;s expectations—and therefore the software&apos;s context—can be altered so easily, with something as simple as an animation.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/26113527?byline=0&amp;#x26;portrait=0&amp;#x26;badge=0&amp;#x26;color=ffffff&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Fri, 30 Nov 2012 16:19:51 GMT</pubDate></item><item><title>Steve Jobs on being at Apple</title><link>https://domchristie.co.uk/posts/steve-jobs-on-being-at-apple/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/steve-jobs-on-being-at-apple/</guid><description>&lt;p&gt;I&apos;ve never been a big fan of watching the big Apple launch events, however I&apos;ve found that listening to Steve Jobs talk about working at Apple and developing products is fascinating:&lt;/p&gt;
&lt;iframe allowfullscreen webkitallowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; width=&quot;500&quot; height=&quot;281&quot; src=&quot;https://video-api.wsj.com/api-video/player/v3/iframe.html?guid=70F7CC1D-FFBF-4BE0-BFF1-08C300E31E11&amp;#x26;shareDomain=null&quot;&gt;&lt;/iframe&gt;</description><pubDate>Wed, 21 Nov 2012 23:25:41 GMT</pubDate></item><item><title>On Trying to Please Everyone</title><link>https://domchristie.co.uk/posts/on-trying-to-please-everyone/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/on-trying-to-please-everyone/</guid><description>&lt;blockquote&gt;
&lt;p&gt;When you broadly and arbitrarily extend a product&apos;s functionality to include many constituencies, you increase the cognitive load and overhead for all users.&lt;/p&gt;
&lt;p&gt;… If you try to design  an automobile that pleases every possible driver, you end up with a car with every possible feature, but pleases nobody. Software today is too often designed to please too many users, resulting in low satisfaction.&lt;/p&gt;
&lt;cite&gt;Alan Cooper in About Face 3&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Mon, 12 Nov 2012 10:15:29 GMT</pubDate></item><item><title>London and Creativity</title><link>https://domchristie.co.uk/posts/london-and-creativity/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/london-and-creativity/</guid><description>&lt;blockquote&gt;
&lt;p&gt;London is such a constantly evolving city. It has many layers of systems in place, but nothing really quite works.&lt;/p&gt;
&lt;p&gt;If you&apos;re working in an environment which doesn&apos;t necessarily work very well, it&apos;s a great environment to try and make things work well. We need contrast and tension to be able to create.&lt;/p&gt;
&lt;cite&gt;Sam Hecht&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/rptGJ8ALQYI?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Tue, 30 Oct 2012 13:38:54 GMT</pubDate></item><item><title>MP3s vs. records; printed books vs. e-books …</title><link>https://domchristie.co.uk/posts/mp3s-vs-records-printed-books-vs-e-books/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/mp3s-vs-records-printed-books-vs-e-books/</guid><description>&lt;blockquote&gt;&lt;p&gt;I think most of the blah-blahing about MP3s versus records (or printed books vs. e-books) is a mix of honest-to-God personal preference and sheer sentimentalism. I think we all need to shut up about this, because nothing anyone writes or says is going to change any minds. Most of the drum-beating amounts to snobbery for being part of a grand tradition or arrogance for being an early adopter. Both are equally foolish things to be prideful about. Find what works for you, and be happy with it. Music is fun and nourishing. Let it be.&lt;/p&gt;&lt;cite&gt;Frank Chimero in &lt;a href=&quot;http://frankchimero.com/blog/2012/10/siamese-dream/&quot;&gt;Siamese Dream&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Guilty.&lt;/p&gt;</description><pubDate>Sat, 27 Oct 2012 10:29:00 GMT</pubDate></item><item><title>-- Please select --</title><link>https://domchristie.co.uk/posts/please-select/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/please-select/</guid><description>&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/please-select.png&quot; alt=&quot;List of title options on TFL complaint form&quot;&gt;</description><pubDate>Sat, 20 Oct 2012 09:43:29 GMT</pubDate></item><item><title>Motivation</title><link>https://domchristie.co.uk/posts/motivation/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/motivation/</guid><description>&lt;blockquote&gt;
&lt;p&gt;… there was this group comedians and they were like Olympus, and I wanted to be one them; and I didn’t care if I sucked at it.&lt;/p&gt;
&lt;cite&gt;Louis C.K. on Talking Funny&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Tue, 16 Oct 2012 07:35:00 GMT</pubDate></item><item><title>Alternative… Electronica…</title><link>https://domchristie.co.uk/posts/alternative-electronica/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/alternative-electronica/</guid><description>&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/alternative-electronica.png&quot; alt=&quot;Alternative… Electronica… iTunes listing&quot;&gt;</description><pubDate>Thu, 11 Oct 2012 21:22:00 GMT</pubDate></item><item><title>Using Backbone.js Class Properties as Data Stores: Part 2</title><link>https://domchristie.co.uk/posts/using-backbone-js-class-properties-as-data-stores-part-2/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/using-backbone-js-class-properties-as-data-stores-part-2/</guid><description>&lt;div class=&quot;alert&quot;&gt;
&lt;p&gt;A Backbone plugin version of the following can now be found on the &lt;a href=&quot;https://github.com/domchristie/backbone-store-collection&quot;&gt;backbone-store-collection GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Previously I demonstrated &lt;a href=&quot;http://domchristie.co.uk/posts/31&quot;&gt;a pattern to add basic data stores to Backbone models&lt;/a&gt;. In this post I&apos;ll improve this pattern, extending the store&apos;s &lt;code&gt;get&lt;/code&gt; method to fetch a model from the server if it&apos;s not stored locally.&lt;/p&gt;
&lt;p&gt;We&apos;ll want the API to look something like this:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Blog.Models.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Post&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({ id: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// model returned from local collection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    model &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post; &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// model fetched from the server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the new &lt;code&gt;get&lt;/code&gt; adds a second parameter, allowing for success/error callbacks.&lt;/p&gt;
&lt;p&gt;First we&apos;ll try and retrieve the model from the local store, this requires calling the original &lt;code&gt;get&lt;/code&gt; (super). If it&apos;s found, we just invoke the &lt;code&gt;success&lt;/code&gt; callback. Otherwise we create a new model with the id that was passed in, fetch that model from the server, then invoke the appropriate callback. (On &lt;code&gt;error&lt;/code&gt;, the blank model is removed from the store.)&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Collections.Posts &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Collection.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; modelFromStore &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      Backbone.Collection.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.get.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(modelFromStore) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      options.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(modelFromStore);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; newModel &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({ id: id }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          _this &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      newModel.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        success: options.success,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #FFAB70&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          _this.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(model);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;          options.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(model, response);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  url: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;/posts&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ve created Backbone plugin for this, available from the &lt;a href=&quot;https://github.com/domchristie/backbone-store-collection&quot;&gt;backbone-store-collection GitHub repo&lt;/a&gt;. So rather than copying the code above, you can simply do something like:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Collections.Posts &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.StoreCollection.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  url: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF&quot;&gt;&apos;/posts&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Models still need to be manually added to the store: see the &lt;a href=&quot;https://github.com/domchristie/backbone-store-collection/blob/master/README.md&quot;&gt;project readme&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Fri, 31 Aug 2012 15:04:38 GMT</pubDate></item><item><title>Using Backbone.js Class Properties as Data Stores</title><link>https://domchristie.co.uk/posts/using-backbone-js-class-properties-as-data-stores/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/using-backbone-js-class-properties-as-data-stores/</guid><description>&lt;div class=&quot;alert&quot;&gt;
&lt;p&gt;Update: a Backbone plugin version of the following pattern can be found on the &lt;a href=&quot;https://github.com/domchristie/backbone-modelling&quot;&gt;backbone-modelling GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I&apos;ve been looking into &lt;a href=&quot;http://emberjs.com/&quot;&gt;ember.js&lt;/a&gt; recently and really liked the look of &lt;a href=&quot;https://github.com/emberjs/data&quot;&gt;Ember Data&lt;/a&gt;: a library for loading and storing models from a persistence layer. It has a nice &lt;a href=&quot;http://guides.rubyonrails.org/active_record_querying.html&quot;&gt;ActiveRecord&lt;/a&gt;-like API for querying models, fetching any models from the server that have not been created or stored locally.&lt;/p&gt;
&lt;p&gt;It&apos;s something I&apos;ve emulated (very basically) in previous &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; projects, so it&apos;s nice to see it implemented so completely.&lt;/p&gt;
&lt;p&gt;Inspired on the Ember Data API, I thought it may be worth improving my own implementation, making use of Backbone&apos;s class properties, like so:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;window.Blog &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Models: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Collections: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Views: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  Routers: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Collections.Posts &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Collection.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  model: Blog.Models.Post &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// this will be undefined&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.store.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  store: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Blog.Collections.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Posts&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First we set up the collection, &lt;s&gt;referencing the Post model&lt;/s&gt; (Update: this will be undefined, causing potential problems down the line. See update below). Then we define the Post model itself, which includes a store (as a class property) and adds each instance to this store on initialize. It&apos;s worth noting that this method makes use of Backbone&apos;s &lt;code&gt;extend&lt;/code&gt; function for Backbone classes (see &lt;a href=&quot;http://backbonejs.org/docs/backbone.html#section-160&quot;&gt;annotated source code&lt;/a&gt;), which differs from underscore&apos;s &lt;code&gt;extend&lt;/code&gt; function: instance properties are extended with the first parameter, class properties in the second.&lt;/p&gt;
&lt;p&gt;This sets up a basic store, allowing us to do things like:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post.store.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Blog.Models.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Post&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post.store.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post.store.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;first&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; post; &lt;/span&gt;&lt;span style=&quot;color: #6A737D&quot;&gt;// true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, all the &lt;a href=&quot;http://backbonejs.org/#Collection-Underscore-Methods&quot;&gt;Underscore collection methods&lt;/a&gt; are available on the &lt;code&gt;store&lt;/code&gt; property. Fetching models that are not stored or created locally shouldn&apos;t be too hard to add: a feature for another blog post, perhaps…&lt;/p&gt;
&lt;h2&gt;Update: Adding the model property and memoizing the store&lt;/h2&gt;
&lt;p&gt;This implementation is ok, but it doesn&apos;t allow the Post model to be referenced in the store&apos;s collection. Not ideal.&lt;/p&gt;
&lt;p&gt;To fix this we will include the model property when the collection is instantiated. This requires us to convert the store property to a function that returns the collection, memoizing the collection (in &lt;code&gt;Blog.Model.Post._store&lt;/code&gt;) in the process:&lt;/p&gt;
&lt;pre is:raw=&quot;&quot; class=&quot;astro-code github-dark&quot; style=&quot;background-color: #24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;Blog.Models.Post &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Backbone.Model.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;}, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;._store &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;._store &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; Blog.Collections.&lt;/span&gt;&lt;span style=&quot;color: #B392F0&quot;&gt;Posts&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;, { model: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: #E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Thu, 30 Aug 2012 19:15:33 GMT</pubDate></item><item><title>jQuery Knob and FF Chartwell</title><link>https://domchristie.co.uk/posts/jquery-knob-and-ff-chartwell/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/jquery-knob-and-ff-chartwell/</guid><description>&lt;p&gt;Firstly, a jQuery plugin for creating &lt;a href=&quot;http://anthonyterrien.com/knob/&quot;&gt;dial controls on the web&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;a href=&quot;http://anthonyterrien.com/knob/&quot;&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/knob.png&quot; alt=&quot;jQuery Knob demo&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;—via &lt;a href=&quot;https://twitter.com/#!/auxilit&quot;&gt;@auxilit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Secondly, a rather innovative use of OpenType features to create charts from text:&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/41772735?title=0&amp;#x26;byline=0&amp;#x26;portrait=0&amp;#x26;color=ffffff&quot; width=&quot;500&quot; height=&quot;375&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;—via &lt;a href=&quot;https://twitter.com/#!/aarron&quot;&gt;@aarron&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 18 May 2012 07:12:00 GMT</pubDate></item><item><title>TDS</title><link>https://domchristie.co.uk/posts/tds/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/tds/</guid><description>&lt;p&gt;If you&apos;ve spoken to me in the last 6 months, you may have heard me rant about our old flat: that, at times, it had no running water; that the landlord/estate agent were totally unprofessional in dealing with the problem; and that they then had the audacity to push to get the flat professionally cleaned.&lt;/p&gt;
&lt;p&gt;On Saturday we heard back from The Dispute Service (TDS) who were holding the £150 that was charged to clean the flat. We received £120 of that back, which I&apos;m very happy with, and it&apos;s a huge relief that it&apos;s all over.&lt;/p&gt;
&lt;p&gt;The report, in parts, makes for some satisfying reading:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[The £150] cleaning invoice includes work which could not possibly have been undertaken such as cleaning an extractor and hood and kitchen tiles when in fact there is no extractor or tiling in the kitchen.&lt;/p&gt;
&lt;p&gt;There is no specific obligation on the tenants to have the flat professionally cleaned … It is not sufficient for a landlord to rely solely on a statement of claim or an obligation in the tenancy agreement … the landlord must support their claim with objective evidence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Although, it did have to end with something a little ridiculous:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am of the opinion that the landlord is not entitled to the full cost of a professional clean but that she is entitled to be compensated [£30] for the cost of cleaning the tarnished tap, the [discoloured] washing machine seal, and the spot stains from the rug&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The cleaning invoice didn&apos;t mention any of that.&lt;/p&gt;</description><pubDate>Mon, 14 May 2012 08:10:00 GMT</pubDate></item><item><title>Slowness</title><link>https://domchristie.co.uk/posts/slowness/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/slowness/</guid><description>&lt;blockquote&gt;
&lt;p&gt;The trouble with the rat race is that even if you win, you&apos;re still a rat&lt;/p&gt;
&lt;cite&gt;Lily Tomlin&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whilst looking for a synonym for &quot;slowness&quot; I came across &lt;a href=&quot;http://www.theworldinstituteofslowness.com&quot;&gt;The World Institute of Slowness&lt;/a&gt;. It has some great quotes (like the one above), and some interesting resources referencing physicist Richard Feynman, and Andy Goldsworthy:&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 339&quot; src=&quot;https://www.youtube-nocookie.com/embed/O9TyHzP-8b8?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Sat, 28 Apr 2012 19:05:00 GMT</pubDate></item><item><title>Badly Drawn Boy—My Friend Cubilas</title><link>https://domchristie.co.uk/posts/badly-drawn-boy-my-friend-cubilas/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/badly-drawn-boy-my-friend-cubilas/</guid><description>&lt;p&gt;From EP3, 1998.&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 339&quot; src=&quot;https://www.youtube-nocookie.com/embed/tsUVjImePkQ?rel=0&amp;#x26;showinfo=0&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Wed, 25 Apr 2012 08:09:00 GMT</pubDate></item><item><title>Ampersand (infinite)</title><link>https://domchristie.co.uk/posts/ampersand-infinite/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/ampersand-infinite/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/7092821191/&quot; title=&quot;ampersand by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7248/7092821191_3ace0dc21d.jpg&quot; alt=&quot;ampersand&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Thu, 19 Apr 2012 08:07:00 GMT</pubDate></item><item><title>Stewart Lee on University Funding and the Arts</title><link>https://domchristie.co.uk/posts/stewart-lee-on-university-funding-and-the-arts/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/stewart-lee-on-university-funding-and-the-arts/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I think the withdrawal of the grant and the implication of student loans, necessarily limits people that want vocational careers, and produces a generation of people who feel that the only purpose of education is to earn money. &lt;/p&gt;
&lt;cite&gt;Stewart Lee&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/JDEZ2h41t0I?rel=0&amp;#x26;modestbranding=1&amp;#x26;autohide=1&amp;#x26;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</description><pubDate>Mon, 16 Apr 2012 07:55:00 GMT</pubDate></item><item><title>London, sometimes</title><link>https://domchristie.co.uk/posts/london-sometimes/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/london-sometimes/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6920922636/&quot; title=&quot;window by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7062/6920922636_c53288acfd.jpg&quot; alt=&quot;window&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6920923422/&quot; title=&quot;three by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7136/6920923422_63b774c405.jpg&quot; alt=&quot;three&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/7067004131/&quot; title=&quot;rug by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7081/7067004131_d62939453b.jpg&quot; alt=&quot;rug&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/7067002631/&quot; title=&quot;man bites nails by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7208/7067002631_27f9a49c9d.jpg&quot; alt=&quot;man bites nails&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6920923896/&quot; title=&quot;pearl by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5272/6920923896_df35f04f73.jpg&quot; alt=&quot;pearl&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Wed, 11 Apr 2012 07:59:00 GMT</pubDate></item><item><title>Innovation Comes From Saying No</title><link>https://domchristie.co.uk/posts/innovation-comes-from-saying-no/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/innovation-comes-from-saying-no/</guid><description>&lt;blockquote&gt;
&lt;p&gt;[Innovation] comes from saying no to 1,000 things to make sure we don&apos;t get on the wrong track or try to do too much. We&apos;re always thinking about new markets we could enter, but it&apos;s only by saying no that you can concentrate on the things that are really important.&lt;/p&gt;
&lt;cite&gt;Steve Jobs, &lt;span class=&quot;lower byline&quot;&gt;from&lt;/span&gt; &lt;a href=&quot;http://www.businessweek.com/bwdaily/dnflash/oct2004/nf20041012_4018_db083.htm&quot;&gt;The Seed of Apple&apos;s Innovation&lt;/a&gt; &lt;div&gt;&lt;span class=&quot;lower byline&quot;&gt;via&lt;/span&gt; &lt;a href=&quot;http://gettingreal.37signals.com/ch05_Hold_the_Mayo.php&quot;&gt;Getting Real: Hold the Mayo&lt;/a&gt;&lt;/div&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Mon, 09 Apr 2012 18:17:00 GMT</pubDate></item><item><title>Music from Japan</title><link>https://domchristie.co.uk/posts/music-from-japan/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/music-from-japan/</guid><description>&lt;p&gt;In March, I listened to music from Japan. I&apos;d just bought Shigeto&apos;s excellent &lt;a title=&quot;Lineage Release on Ghostly Site&quot; href=&quot;http://ghostly.com/releases/lineage-ep&quot;&gt;Lineage&lt;/a&gt; (and got &lt;a href=&quot;http://www.theghostlystore.com/collections/clothing/products/lineage-tee&quot;&gt;the t-shirt&lt;/a&gt;), so I felt it was a suitable time to investigate music from other Japanese artists.&lt;/p&gt;
&lt;p&gt;I plugged in &quot;Takagi Masakatsu&quot; into Last.fm (an artist I discovered from my &lt;a title=&quot;FatCat playlist on Spotify&quot; href=&quot;http://open.spotify.com/user/bonanza9/playlist/0ZRuMeKCRaBkfkxv8yXh43&quot;&gt;FatCat inspired month&lt;/a&gt;), and took note of anything which tickled my fancy.&lt;/p&gt;
&lt;p&gt;First of all, &lt;a title=&quot;Sakerock on YouTube&quot; href=&quot;http://www.youtube.com/results?search_query=sakerock&amp;#x26;oq=sakerock&amp;#x26;aq=f&amp;#x26;aqi=g1&amp;#x26;aql=&amp;#x26;gs_l=youtube.3..0.1401l3626l0l3750l12l12l1l0l0l0l301l1185l4j6j0j1l11l0.&quot;&gt;Sakerock&lt;/a&gt; blew me away. I could not stop listening to Kaishain (see video below). The rest of the album is excellent, too (but unfortunately not on Spotify).&lt;/p&gt;
&lt;iframe style=&quot;--width: 500; --height: 281&quot; src=&quot;https://www.youtube-nocookie.com/embed/RBXM4f6xW8M?rel=0&amp;#x26;showinfo=0&amp;#x26;showsearch=0&amp;#x26;modestbranding=1&amp;#x26;autohide=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;I also discovered Cornelius, whose album, &lt;a title=&quot;Point on Spotify&quot; href=&quot;http://open.spotify.com/album/5lSdPoQZHkcLVsUZPUKFTD&quot;&gt;Point&lt;/a&gt;, is brilliant.&lt;/p&gt;
&lt;p&gt;I&apos;ve put together &lt;a href=&quot;http://open.spotify.com/user/bonanza9/playlist/6yygRikWBgZ65CWonmHa57&quot;&gt;a Spotify playlist of this month&apos;s Japanese music&lt;/a&gt;, which also includes Sakura by Susumu Yokota. Enjoy!&lt;/p&gt;</description><pubDate>Tue, 03 Apr 2012 12:09:43 GMT</pubDate></item><item><title>Good Morning!</title><link>https://domchristie.co.uk/posts/good-morning/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/good-morning/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6861979474/&quot; title=&quot;Good Morning! by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7239/6861979474_e0f701cae6.jpg&quot; alt=&quot;Good Morning!&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Fri, 23 Mar 2012 10:35:05 GMT</pubDate></item><item><title>A Collection of Lyrics from David Shrigley&apos;s &apos;Worried Noodles&apos;</title><link>https://domchristie.co.uk/posts/a-collection-of-lyrics-from-david-shrigley-s-worried-noodles/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/a-collection-of-lyrics-from-david-shrigley-s-worried-noodles/</guid><description>&lt;p&gt;In anticipation of my visit to the &lt;a href=&quot;http://ticketing.southbankcentre.co.uk/find/hayward-gallery-and-visual-arts/other-art-on-site/tickets/david-shrigley-brain-activity-61752&quot;&gt;David Shrigley exhibition at the Hayward&lt;/a&gt;, here are a collection of my favourite lyrics from his record, &apos;Worried Noodles&apos;. Lyrics found on &lt;a href=&quot;http://www.moorestevie.com/3/shriglyrics2.html&quot;&gt;moorestevie.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;http://open.spotify.com/track/1uSd8tqGADIgDaUwkjL8FD&quot;&gt;A Truce (music by Max Tundra)&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;d like to declare a truce.
&lt;br&gt;—What&apos;s a truce?
&lt;br&gt;It&apos;s when you agree to stop fighting.
&lt;br&gt;—Have we been fighting?
&lt;br&gt;Yes.
&lt;br&gt;—Are you sure?
&lt;br&gt;Yes.
&lt;br&gt;—When were we fighting?
&lt;br&gt;Just now down there on that plastic mat.
&lt;br&gt;—We weren&apos;t fighting, we were playing &apos;Twister&apos;
&lt;br&gt;Are you sure we weren&apos;t fighting?
&lt;br&gt;—Yes. Twister is a game.
&lt;br&gt;A fighting game?
&lt;br&gt;—No, just an ordinary game.
&lt;br&gt;For soldiers?
&lt;br&gt;—No, well, soldiers can play but there is no fighting.
&lt;br&gt;Soldiers love to fight.
&lt;br&gt;—Well, there is no fighting when you&apos;re playing &apos;Twister&apos;. It&apos;s against the rules.
&lt;br&gt;There are rules?
&lt;br&gt;—Yes, didn&apos;t you know? We&apos;ve been playing for hours. Didn&apos;t you realise?
&lt;br&gt;No. I thought we were fighting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;&lt;a href=&quot;http://open.spotify.com/track/439Bflxiqly3ChqMNd3kk0&quot;&gt;The Wooden Floor (music by James Chadwick)&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The wooden floor is made of wood
&lt;br&gt;And the wood is very good
&lt;br&gt;Oak, we think
&lt;br&gt;The wooden floor is full of grace
&lt;br&gt;And beneath the floor there is a space
&lt;br&gt;Where dirt and bits of stuff reside
&lt;br&gt;And recently, at their side,
&lt;br&gt;A human head
&lt;br&gt;The human head belonged to Pete
&lt;br&gt;Who scuffed the floor
&lt;br&gt;With his giant feet.&lt;/p&gt;
&lt;p&gt;He will not be doing that again
&lt;br&gt;Unless his corpse grows a new head
&lt;br&gt;And comes back to life.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;&lt;a href=&quot;http://open.spotify.com/track/6hhoi7APEciPVyyzUsfkAv&quot;&gt;Squirrel (music by Munch Munch)&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Squirrel squirrel
&lt;br&gt;In the tree
&lt;br&gt;Do me a favour
&lt;br&gt;Collect Nuts for me
&lt;br&gt;Do me a favour
&lt;br&gt;And take the shells off
&lt;br&gt;The nuts
&lt;br&gt;And examine them closely
&lt;br&gt;To check they are not
&lt;br&gt;Rotten
&lt;br&gt;Before you give them to me.&lt;/p&gt;
&lt;p&gt;Nut Nut
&lt;br&gt;Beautiful nut
&lt;br&gt;Salt nut
&lt;br&gt;Spicy nut
&lt;br&gt;You&apos;rea good old nut
&lt;br&gt;And I love you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;&lt;a href=&quot;http://open.spotify.com/track/3OK6lTb13emeC4yIL8qirX&quot;&gt;No (music by Franz Ferdinand)&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;No no no no no no no no
&lt;br&gt;No hair
&lt;br&gt;No no no no no no no no
&lt;br&gt;No eyes
&lt;br&gt;No no no no no no no no
&lt;br&gt;No teeth
&lt;br&gt;No no no no no no no no
&lt;br&gt;No brains
&lt;br&gt;No no no no no no no no
&lt;br&gt;No arms
&lt;br&gt;No no no no no no no no
&lt;br&gt;No legs
&lt;br&gt;No no no no no no no no
&lt;br&gt;No feet
&lt;br&gt;No no no no no no no no
&lt;br&gt;No shoes
&lt;br&gt;No no no no no no no no
&lt;br&gt;No thanks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also: &lt;a href=&quot;http://open.spotify.com/track/3KpvAz2JzQb64c44g4HTGD&quot;&gt;A Sentimental Song, by Cotton Candy&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 22 Mar 2012 23:06:09 GMT</pubDate></item><item><title>Pain</title><link>https://domchristie.co.uk/posts/pain/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/pain/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6855294556/&quot; title=&quot;pain by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm7.staticflickr.com/6234/6855294556_7a5c3a4c3d_c.jpg&quot; alt=&quot;pain&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Tue, 20 Mar 2012 23:36:05 GMT</pubDate></item><item><title>The Experience of Signing up to O2 Home Broadband</title><link>https://domchristie.co.uk/posts/the-experience-of-signing-up-to-o2-home-broadband/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-experience-of-signing-up-to-o2-home-broadband/</guid><description>&lt;div class=&quot;alert&quot;&gt;&lt;p&gt;Note: I recently promised myself that I&apos;d try not to moan as much, particularly on the web. So this is just a review, not a rant ;).&lt;/p&gt;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;https://domchristie.s3.amazonaws.com/confusing-o2.png&quot; alt=&quot;Confusing messages from O2 broadband&quot;&gt;&lt;/div&gt;
&lt;p&gt;One of the firsts tasks after moving into a new flat is to sort out an internet connection. It seems rather silly that setting up a TV in a new flat is just a case of &quot;plugging it in&quot;, yet trying to connect to the web requires time/research/decisions/stress, even before &quot;plugging it in&quot; (which is nowhere near as simple as with a TV). Anyway, after plenty of phone calls and maths, we discovered that O2 Home Phone and Broadband had the best balance of cost/installation efficiency.&lt;/p&gt;
&lt;p&gt;I spoke to O2 sales a couple of times, and they were very nice. They sorted out a phone and broadband package that I was happy with and answered some of my questions. The package was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;12 months &quot;half-price&quot; broadband (as an existing O2 customer) at £6.25/month&lt;/li&gt;
&lt;li&gt;line-rental at £9/month&lt;/li&gt;
&lt;li&gt;as an existing O2 customer I also received a &quot;half-price&quot; installation (£43 rather than £86), and no connection fee&lt;/li&gt;
&lt;li&gt;and a &quot;free&quot; £25 M&amp;#x26;S voucher&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also confirmed a date for a BT engineer to carry out the installation at the property (5th March).&lt;/p&gt;
&lt;p&gt;After the phone call it started to get a bit annoying. I received the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a text message with my &quot;Mobile Discount Code&quot;, which I was told to ignore. Not ideal, but easy enough.&lt;/li&gt;
&lt;li&gt;an email confirming my order&lt;/li&gt;
&lt;li&gt;a text message confirming my order with a link to track the router delivery&lt;/li&gt;
&lt;li&gt;an email detailing the expected broadband &quot;connection&quot; date (6th March)&lt;/li&gt;
&lt;li&gt;a text message with the expected broadband &quot;activation&quot; date&lt;/li&gt;
&lt;li&gt;an email noting when my home phone service will be set up, along with the date and time the BT engineer is expected&lt;/li&gt;
&lt;li&gt;an email confirming that my direct debit was being set up&lt;/li&gt;
&lt;li&gt;a text message confirming that my direct debit was being set up&lt;/li&gt;
&lt;li&gt;a text message confirming the date/time the engineer is set to come out&lt;/li&gt;
&lt;li&gt;a text message with the &quot;Good News!&quot; that my router was on its way&lt;/li&gt;
&lt;li&gt;an email also notifying me that the router was on its way&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Four emails and five text messages (+ another one to ignore), giving me information I already knew. Rather a lot of messages.&lt;/p&gt;
&lt;p&gt;A few days before the installation, I had a missed call/voicemail from BT, again confirming the installation date. The same day I received the following:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;O2: Sorry but your home phone order is taking a bit longer than we thought. It should be sorted soon. Check your email for further details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The email I read:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;O2: Your home phone start date&apos;s been delayed&lt;/em&gt;
… We&apos;re working on it right now and will let you know your new connection date as soon as possible. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now I was a bit worried and confused but suspected that this was just an automated notification when an order goes beyond a certain number of days. Not wanting to risk anything though, I emailed them just to make sure. Luckily this was the case, and so another couple of notifications to ignore.&lt;/p&gt;
&lt;p&gt;On to the installation day. I took the day off to give the engineer access to the flat (and so I&apos;d not be charged a rearrangement fee, as I&apos;d been warned). Then without any sign of an engineer, I received a text (echoed by an email, of course):&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;O2: Good News, we&apos;ve connected you early.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I rang them just to confirm, and after being cut off once, the O2 representative said that sometimes the engineer only has to visit the nearest distribution centre. Nice to let us know. An email or text would&apos;ve been nice.&lt;/p&gt;
&lt;p&gt;I&apos;m happy that we have broadband at home, though slightly bemused that it took two weeks, cost £43 (&quot;half price!&quot;), and required me to take a day off, all for a guy to (seemingly) flick a switch somewhere else.&lt;/p&gt;
&lt;p&gt;I realise that this nowhere near the worst experience anyone has had with a broadband installation. But as the whole thing went to schedule, I&apos;m asking myself, what is going on inside O2&apos;s systems that makes the process so irritating and confusing?&lt;/p&gt;</description><pubDate>Tue, 06 Mar 2012 22:20:34 GMT</pubDate></item><item><title>Rd.</title><link>https://domchristie.co.uk/posts/rd/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/rd/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6800222818/&quot; title=&quot;Rd. by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7179/6800222818_c27e121aff.jpg&quot; alt=&quot;Rd.&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Fri, 02 Mar 2012 14:26:13 GMT</pubDate></item><item><title>The Best and Worst Sentence I&apos;ve Ever Read</title><link>https://domchristie.co.uk/posts/the-best-and-worst-sentence-i-ve-ever-read/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-best-and-worst-sentence-i-ve-ever-read/</guid><description>&lt;p&gt;My girlfriend and I will soon be moving flat—to place with such luxuries as running water (fingers-crossed). Anyway, we&apos;ve just had the tenancy agreement for our new place sent through. It&apos;s short (only four pages: one-fifth the length of our current contract), so I went through it on my short train journey home. I could hardly contain myself. In fact, I couldn&apos;t contain myself—I was laughing so hard.&lt;/p&gt;
&lt;p&gt;I won&apos;t go through every poorly constructed sentence: it&apos;d take too long, but here are a couple of gems.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Tenant shall:-&lt;/strong&gt;  …
&lt;br&gt;
(c) Use the property in a tenant-like manner
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;… and the sentence that had me in tears:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
(t) Not do or suffer to be done any act or thing which may be a nuisance or annoyance to the Landlord or to the occupiers of any adjoining premises or which may vitiate any insurance of the Property or the contents thereof against fire or otherwise increase the ordinary premium thereon and in particular without prejudice to the generality of the foregoing not to use or play any electrical or musical instruments of any kind or practice any singing in the Property so as to cause annoyance to nearby residents or occupiers or at all so as to be audible outside the Property between the hours of 11pm and 9am
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Somehow, it simultaneously manages to be the best and worst sentence I&apos;ve ever read.&lt;/p&gt;</description><pubDate>Tue, 07 Feb 2012 21:08:58 GMT</pubDate></item><item><title>T</title><link>https://domchristie.co.uk/posts/t/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/t/</guid><description>&lt;figure&gt;&lt;a href=&quot;http://www.flickr.com/photos/domchristie/6806517067/&quot; title=&quot;T by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7006/6806517067_a5dc298293.jpg&quot; alt=&quot;T&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Thu, 02 Feb 2012 13:14:46 GMT</pubDate></item><item><title>I Haven&apos;t Seen Most Films</title><link>https://domchristie.co.uk/posts/i-haven-t-seen-most-films/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/i-haven-t-seen-most-films/</guid><description>&lt;p&gt;For whatever reasons, going to the cinema/watching films has never been something I&apos;ve done much of. It&apos;s not that I don&apos;t enjoy it, but I&apos;ve often felt that a cinema visit isn&apos;t worth it (a feeling that was reinforced when I was invited to watch Meet the Fockers&lt;sup&gt;&lt;a id=&quot;r14.1&quot; href=&quot;#fn14.1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;
&lt;p&gt;I often found it rather embarrassing to admit I hadn&apos;t seen an absolute classic. Now I&apos;m quite open about the fact that I haven&apos;t seen most films (or rather, I haven&apos;t seen most of the films that almost everyone I know has seen). It&apos;s even become an interesting conversation starter: people are amazed when I reel off some of the films I&apos;ve yet to see (just you wait!).&lt;/p&gt;
&lt;p&gt;It also sparked off an idea amongst friends to create a documentary about me watching classic films. It was a rather ambitious New Year&apos;s resolution, that we started but never finished.&lt;/p&gt;
&lt;h2&gt;Films I Haven&apos;t Seen&lt;/h2&gt;
&lt;p&gt;So here&apos;s the list of films I haven&apos;t seen (but feel I really should have).&lt;br&gt;A &lt;s&gt;strikethrough&lt;/s&gt; denotes films I saw whilst making the documentary mentioned above. As you can see, we didn&apos;t get very far.&lt;/p&gt;
&lt;ul class=&quot;checklist&quot;&gt;
&lt;li&gt;
Francis Ford Coppola&apos;s:
&lt;ul&gt;
&lt;li class=&quot;checked&quot;&gt;Godfather pt.1&lt;/li&gt;
&lt;li class=&quot;checked&quot;&gt;Godfather pt.2 (should I bother with pt.3?)&lt;/li&gt;
&lt;li&gt;Apocalypse Now&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Kubrick&apos;s:
&lt;ul&gt;
&lt;li&gt;2001: A Space Odyssey&lt;/li&gt;
&lt;li&gt;Clockwork Orange&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Tarantino&apos;s:
&lt;ul&gt;
&lt;li&gt;Pulp Fiction&lt;/li&gt;
&lt;li&gt;Reservoir Dogs&lt;/li&gt;
&lt;li class=&quot;checked&quot;&gt;Jackie Brown&lt;/li&gt;
&lt;li&gt;Kill Bill vol.1&lt;/li&gt;
&lt;li&gt;Kill Bill vol.2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Steven Spielberg&apos;s:
&lt;ul&gt;
&lt;li&gt;Jaws&lt;/li&gt;
&lt;li&gt;Schindler&apos;s List&lt;/li&gt;
&lt;li&gt;Back to the Future 1&lt;/li&gt;
&lt;li&gt;Back to the Future 2&lt;/li&gt;
&lt;li&gt;Back to the Future 3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Ridley Scott&apos;s:
&lt;ul&gt;
&lt;li&gt;Blade Runner&lt;/li&gt;
&lt;li&gt;Alien (or any in the Alien series…)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
James Cameron&apos;s:
&lt;ul&gt;
&lt;li&gt;Aliens&lt;/li&gt;
&lt;li&gt;Terminator&lt;/li&gt;
&lt;li&gt;Terminator 2&lt;/li&gt;
&lt;li&gt;Terminator 3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Wes Anderson&apos;s:
&lt;ul&gt;
&lt;li&gt;Rushmore&lt;/li&gt;
&lt;li class=&quot;checked&quot;&gt;The Royal Tenenbaums&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Coen brothers&apos;:
&lt;ul&gt;
&lt;li class=&quot;checked&quot;&gt;Barton Fink&lt;/li&gt;
&lt;li class=&quot;checked&quot;&gt;Fargo&lt;/li&gt;
&lt;li&gt;The Big Lebowski&lt;/li&gt;
&lt;li&gt;No Country for Old Men&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Notable Films I have Seen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Lord of the Rings Trilogy&lt;/li&gt;
&lt;li&gt;The Star Wars series (apart from Episode II: Attack of the Clones)&lt;/li&gt;
&lt;li&gt;Ghostbusters (and maybe Ghostbusters 2?)&lt;/li&gt;
&lt;li&gt;Some of the Spielberg&apos;s: E.T., The Indiana Jones series (I think), Saving Private Ryan&lt;/li&gt;
&lt;li&gt;Gladiator&lt;/li&gt;
&lt;li&gt;Toy Story (although maybe not Toy Story 2 and dipped in-and-out of Toy Story 3)&lt;/li&gt;
&lt;li&gt;Memento (probably my favourite film)&lt;/li&gt;
&lt;li&gt;Eternal Sunshine of the Spotless Mind&lt;/li&gt;
&lt;li&gt;City of God&lt;/li&gt;
&lt;li&gt;Amelie&lt;/li&gt;
&lt;li&gt;Some of the Wes Anderson films: The Life Aquatic, The Darjeeling Ltd., Fantastic Mr. Fox&lt;/li&gt;
&lt;li&gt;Fightclub&lt;/li&gt;
&lt;li&gt;Inception&lt;/li&gt;
&lt;li&gt;Senna (probably the best film I&apos;ve seen recently)&lt;/li&gt;
&lt;li&gt;Up&lt;/li&gt;
&lt;li&gt;Avatar (didn&apos;t really enjoy)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Are there any other &lt;em&gt;classics&lt;/em&gt; I should watch? Let me know. &lt;a href=&quot;https://twitter.com/#!/domchristie/&quot;&gt;@domchristie&lt;/a&gt;.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;p id=&quot;fn14.1&quot;&gt;&lt;a href=&quot;#r14.1&quot;&gt;[1]&lt;/a&gt; I couldn&apos;t say no. It was awful.&lt;/p&gt;
&lt;/section&gt;</description><pubDate>Mon, 30 Jan 2012 21:36:58 GMT</pubDate></item><item><title>From Lato to Calluna Sans</title><link>https://domchristie.co.uk/posts/from-lato-to-calluna-sans/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/from-lato-to-calluna-sans/</guid><description>&lt;figure style=&quot;margin-left: 0; margin-right: 0;&quot;&gt;&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/lato-vs-calluna.png&quot; alt=&quot;A comparison of Lato and Calluna Sans&quot;&gt;&lt;figcaption&gt;No, you&apos;re not at the opticians. Lato (L), Calluna Sans(R).&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I really like &lt;a href=&quot;http://www.google.com/webfonts/specimen/Lato&quot;&gt;Lato&lt;/a&gt;. It was the typeface I used for headings on this site. That was until I fancied a change and discovered &lt;span class=&quot;tk-calluna&quot; style=&quot;font-style: italic&quot;&gt;Calluna&lt;/span&gt; and &lt;span class=&quot;tk-calluna-sans&quot;&gt;Calluna Sans&lt;/span&gt;.&lt;/p&gt;
&lt;div&gt;&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/lato-calluna-in-context.png&quot; alt=&quot;A comparison of Lato and Calluna Sans in context&quot;&gt;&lt;/div&gt;
&lt;p&gt;I prefer straightness of the leg on Calluna Sans&apos; uppercase &lt;span class=&quot;tk-calluna-sans&quot;&gt;R&lt;/span&gt;, and the way the uppercase &lt;span class=&quot;tk-calluna-sans&quot;&gt;J&lt;/span&gt; drops below the baseline. The uppercase &lt;span class=&quot;tk-calluna-sans&quot;&gt;M&lt;/span&gt; nearly put me off: I usually prefer vertical stems to sloped, but the apex (in the middle) is cleaner than that belonging to Lato, and overall it appears less imposing.&lt;/p&gt;
&lt;p&gt;Thoughts? &lt;a href=&quot;https://twitter.com/domchristie&quot;&gt;@domchristie&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 26 Jan 2012 22:12:59 GMT</pubDate></item><item><title>Trustworthy Fonts</title><link>https://domchristie.co.uk/posts/trustworthy-fonts/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/trustworthy-fonts/</guid><description>&lt;p&gt;I&apos;m currently reading &lt;a href=&quot;http://www.simongarfield.com/pages/books/just_my_type.htm&quot;&gt;Just My Type&lt;/a&gt; by Simon Garfield. &lt;a href=&quot;http://www.amazon.co.uk/Just-My-Type-About-Fonts/dp/1846683025/ref=sr_1_1?ie=UTF8&amp;#x26;qid=1327262320&amp;#x26;sr=8-1&quot;&gt;Buy it&lt;/a&gt;: it&apos;s very good and has some nice little nuggets, like this one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We tend to treat the traditional and familiar as trustworthy. We are dubious of fonts that alert us to their difference, or fonts that seem to be trying too hard. We don&apos;t like being consciously sold things or paying for fancy design we don&apos;t need.&lt;/p&gt;
&lt;cite&gt;Simon Garfield, in &lt;a href=&quot;http://www.simongarfield.com/pages/books/just_my_type.htm&quot;&gt;Just My Type&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Sun, 22 Jan 2012 20:06:08 GMT</pubDate></item><item><title>New Project and Open Source Stuff</title><link>https://domchristie.co.uk/posts/new-project-and-open-source-stuff/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/new-project-and-open-source-stuff/</guid><description>&lt;p&gt;I&apos;ve been pretty busy recently working on a new side-project: a nice bookmarking/scrapbooking tool, which gives me the chance to delve deeper into both server-side and front-end technologies. It&apos;s being built in Rails 3.1 and Backbone (with CoffeeScript), and includes plenty of pretty CSS bits (webfonts, transitions etc). It&apos;ll hopefully have a bookmarklet, and a decent API … we&apos;ll see.&lt;/p&gt;
&lt;p&gt;There&apos;s also been some activity on my open source projects, which is amazing. &lt;a href=&quot;https://github.com/domchristie/to-markdown&quot;&gt;to-markdown&lt;/a&gt; has had some important updates (and has gained a few followers along the way!). Thanks to &lt;a href=&quot;https://github.com/bergie&quot;&gt;Henri Bergius&lt;/a&gt;, it now runs on Node.js (another technology I need to get properly stuck into). &lt;a href=&quot;https://github.com/domchristie/ios-placeholder&quot;&gt;ios-placeholder&lt;/a&gt; has been updated thanks to &lt;a href=&quot;https://github.com/theinterned&quot;&gt;Ned Schwartz&lt;/a&gt;, and &lt;a href=&quot;https://github.com/domchristie/juration&quot;&gt;juration&lt;/a&gt; will be getting the &apos;chrono&apos; format support soon (thanks to &lt;a href=&quot;https://github.com/jotto&quot;&gt;Jonathan Otto&lt;/a&gt;). Hopefully I&apos;ll get these pull requests merged in soon: my head has been stuck in that little side-project of mine!&lt;/p&gt;
&lt;p&gt;In other news, I&apos;m giving &lt;a href=&quot;http://www.sublimetext.com/2&quot;&gt;Sublime Text 2&lt;/a&gt; a go (&lt;a href=&quot;http://twitter.com/#!/samoli&quot;&gt;Sam&lt;/a&gt; has not stopped going on about it!). I&apos;m getting into it, thanks to &lt;a href=&quot;http://opensoul.org/blog/archives/2012/01/12/getting-started-with-sublime-text-2/&quot;&gt;this Sublime Text 2 guide&lt;/a&gt;, and &lt;a href=&quot;http://twitter.com/sublimetips&quot;&gt;@sublimetips&lt;/a&gt; twitter feed. One essential package for those who regularly deal with &lt;code&gt;erb&lt;/code&gt; views: &lt;a href=&quot;https://github.com/eddorre/SublimeERB&quot;&gt;SublimeERB&lt;/a&gt; (available via Package Control, but don&apos;t forget to add the key bindings, as detailed in the readme).&lt;/p&gt;</description><pubDate>Fri, 20 Jan 2012 12:06:39 GMT</pubDate></item><item><title>Taxes</title><link>https://domchristie.co.uk/posts/taxes/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/taxes/</guid><description>&lt;p&gt;I&apos;ve been meaning to get this quotation down for ages. I heard it on Radio 4&apos;s Chain Reaction programme back in September last year, when Kevin Eldon interviewed Mark Steel.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think lampposts soon will have little meters on, and you&apos;ll put 5p in and it&apos;ll give you just enough light to get to the next one: &quot;Why should I pay for someone else&apos;s light? I&apos;M INDOORS!… bloody fire-brigade — I&apos;m not on fire! I&apos;ll pay when I want carrying over someones shoulder down a smoky bannister!&quot;&lt;/p&gt;
&lt;p&gt;These are the sort of people that go: &quot;What about guide dogs? All the money that gets spent on them! I can&apos;t climb a tree, nobody buys me a gibbon!&quot;&lt;/p&gt;
&lt;cite&gt;Mark Steel, on &lt;a href=&quot;http://www.bbc.co.uk/programmes/b013gfnh&quot;&gt;Chain Reaction&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Thu, 19 Jan 2012 22:17:21 GMT</pubDate></item><item><title>Neuroscience</title><link>https://domchristie.co.uk/posts/neuroscience/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/neuroscience/</guid><description>&lt;p&gt;I don&apos;t plan on writing much about neuroscience(!), but the following quotation caught my ear. It comes from BBC Radio 4&apos;s &lt;a href=&quot;https://www.bbc.co.uk/programmes/b015sqc7&quot;&gt; The Life Scientific&lt;/a&gt; – a series of interviews with scientists about their life and work.&lt;/p&gt;
&lt;p&gt;It&apos;s not a programme I&apos;d usually seek out – it just happens to be on after the Today programme, but every episode I&apos;ve heard has been really interesting, and has got me thinking.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Neuroscience calls itself a science (obviously), but it&apos;s very different from [a physicist&apos;s] science of physics, or a chemist&apos;s science of chemistry, because it&apos;s a set of techniques searching for a common answer, rather than a real structured level of analysis of a scientific problem.&lt;/p&gt;&lt;p&gt;... in physics, the questions are agreed. You could walk into any physicist&apos;s office or lab, and say, &quot;What are the big questions in physics?&quot;, and they&apos;d reel them off: &quot;How did the universe start?&quot;, &quot;What&apos;s matter made of?&quot;; and everyone would agree. But if you ask that question to a neuroscientist, they&apos;d just be puzzled by the question.&lt;/p&gt;&lt;cite&gt;Neuroscientist Colin Blakemore, on &lt;a href=&quot;https://www.bbc.co.uk/iplayer/episode/b016wxtx/The_Life_Scientific_Episode_5/&quot;&gt;The Life Scientific&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;</description><pubDate>Wed, 09 Nov 2011 09:17:00 GMT</pubDate></item><item><title>Found: locked out</title><link>https://domchristie.co.uk/posts/found-locked-out/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/found-locked-out/</guid><description>&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6317826897/&quot; title=&quot;found: locked out by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6113/6317826897_ff3f815d72.jpg&quot; alt=&quot;found: locked out&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sun, 06 Nov 2011 13:06:02 GMT</pubDate></item><item><title>Bletchley Park</title><link>https://domchristie.co.uk/posts/bletchley-park/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/bletchley-park/</guid><description>&lt;p&gt;The BBC are currently running a series on some of the untold stories of World War II. The first was &lt;a href=&quot;https://www.bbc.co.uk/programmes/b016ltm0&quot;&gt;Code-Breakers: Bletchley Park&apos;s Lost Heroes&lt;/a&gt;, and told the story of how one of the most sophisticated codes was broken (the &lt;a href=&quot;https://en.wikipedia.org/wiki/Lorenz_cipher&quot;&gt;Lorenz&lt;/a&gt;), which led to the invention of the first computer. It&apos;s a great watch.&lt;/p&gt;
&lt;p&gt;I&apos;ve visted Bletchley Park a couple of times. It&apos;s a fascinating place, pretty much untouched since the war and well worth a visit.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6293970697/&quot; title=&quot;Bicycles by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6038/6293970697_d141892aaf.jpg&quot; alt=&quot;Bicycles&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6294496524/&quot; title=&quot;Net Curtain by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6037/6294496524_6a4ea54e48.jpg&quot; alt=&quot;Net Curtain&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6294496686/&quot; title=&quot;Hut by dom christie, on Flickr&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6058/6294496686_ac73861fba.jpg&quot; alt=&quot;Hut&quot;&gt;&lt;/a&gt;&lt;/figure&gt;</description><pubDate>Sun, 30 Oct 2011 11:11:00 GMT</pubDate></item><item><title>Nonsense</title><link>https://domchristie.co.uk/posts/nonsense/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/nonsense/</guid><description>&lt;blockquote&gt;
  &lt;p&gt;Talking nonsense the sole privilege mankind possesses over the other organisms. It&apos;s by talking nonsense that one gets to the truth! I talk nonsense, therefore I am human. Not one single truth has ever been arrived at without people first having talked a dozen reams of nonsense, even ten dozen reams of it, and that&apos;s an honourable thing in its own way; well, but we can&apos;t even talk nonsense with our own brains! Talk nonsense to me, by all means, but do it with your own brain, and I shall love you for it. To talk nonsense in one&apos;s own way is almost better than to talk a truth that&apos;s someone else&apos;s; in the first instance you behave like a human being, while in the second you are merely being a parrot!&lt;/p&gt;
  &lt;cite&gt;Razumikhin, in Crime and Punishment&lt;/cite&gt;
&lt;/blockquote&gt;</description><pubDate>Wed, 12 Oct 2011 18:51:00 GMT</pubDate></item><item><title>Ten Years Taking Pictures</title><link>https://domchristie.co.uk/posts/ten-years-taking-pictures/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/ten-years-taking-pictures/</guid><description>&lt;p&gt;Truth be told it&apos;s been &lt;strong&gt;a bit more than ten years taking pictures&lt;/strong&gt;, but that doesn&apos;t make such a good title. Anyway, I thought I&apos;d pick out some photos from the archives and put together a review.&lt;/p&gt;
&lt;h2&gt;1990&lt;span class=&quot;lower&quot;&gt;s&lt;/span&gt;/Early 2000&lt;span class=&quot;lower&quot;&gt;s&lt;/span&gt; — School&lt;/h2&gt;
&lt;p&gt;The first time I can remember taking pictures was some time in the 90s, with a Polaroid 600 camera that my sister and I saved up for. I started studying photography at school when I was 16/17. It began with a William Eggleston / Ansel Adams exhibition at the Hayward. I probably couldn&apos;t have chosen a better exhibition to be my first. Adams one of the greatest landscape photographers of all time; while Eggleston pioneered the use of colour photography as art during the 70s. Both still influence my thoughts when I look through the viewfinder.&lt;/p&gt;
&lt;p&gt;My dad had a nice SLR (like most dads of his generation), and I began shooting a few rolls with it immediately after that first exhibition. I still have these films somewhere, and will post some highlights when I get round to digitising them.&lt;/p&gt;
&lt;p&gt;I was also lucky enough to have access to a couple of dark rooms at school, and was taught how to develop and print black and white film. I developed an interest for urban landscape and night photography, as well as video installations. At the end of year exhibition, the video below was projected onto a clear perspex waterfall.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205570992/&quot; title=&quot;Habitat Building, Bromley&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6022/6205570992_1676b256b9.jpg&quot; alt=&quot;Habitat Building, Bromley&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205571290/&quot; title=&quot;Bromley South Station&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6152/6205571290_9ed00490b5.jpg&quot; alt=&quot;Bromley South Station&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/5919147?title=0&amp;#x26;byline=0&amp;#x26;portrait=0&amp;#x26;color=ffffff&quot; frameborder=&quot;0&quot; width=&quot;500&quot; height=&quot;335&quot; webkitallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2&gt;2004/5 — First Year, Uni&lt;/h2&gt;
&lt;p&gt;I only studied photography for a year, but missed taking pictures when I started university. I received a compact digital camera for Christmas — which I nearly didn&apos;t get after the postman left it in the recycling bin. I got back into photography with this camera, and started to get addicted to Flickr. My favourite photos with this camera are those of the Island of Lindisfarne (below). They may not be the sharpest, or clearest, but I&apos;m pleased with how they feel. They pretty much mirror my memories, which is important to me.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205056265/&quot; title=&quot;Lindisfarne Pilgrmage Poles 1&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6176/6205056265_91d4d87967.jpg&quot; alt=&quot;Lindisfarne Pilgrmage Poles 1&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205056361/&quot; title=&quot;Lindisfarne Pilgrmage Poles 2&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6160/6205056361_214e4ed9d2.jpg&quot; alt=&quot;Lindisfarne Pilgrmage Poles 2&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205571802/&quot; title=&quot;Lindisfarne Pilgrmage Poles 3&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6156/6205571802_4ef8f8bd90.jpg&quot; alt=&quot;Lindisfarne Pilgrmage Poles 3&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;2005/6 — Second Year, Uni&lt;/h2&gt;
&lt;p&gt;Having stumbled across &lt;a href=&quot;https://www.flickr.com/photos/lomokev/&quot;&gt;lomokev on Flickr&lt;/a&gt;, I realised I missed the characteristics of film and the process of taking pictures with it. I swiftly bought a Lomo LC-A on eBay, and started experimenting with Jessops (Agfa) slide film. I&apos;m not a fan of the whole &lt;a href=&quot;https://www.lomography.com/&quot;&gt;lomography&lt;/a&gt; thing, but I can&apos;t say it hasn&apos;t influenced my style.&lt;/p&gt;
&lt;p&gt;This was probably my most productive time taking pictures — I found it hard to pick a few favourites.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205056565/&quot; title=&quot;University of Surrey, Roots&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6164/6205056565_26b97aa71e.jpg&quot; alt=&quot;University of Surrey, Roots&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/3286908487/&quot; title=&quot;West Wickham Bus Stop&quot;&gt;&lt;img src=&quot;https://farm4.static.flickr.com/3492/3286908487_830e37e49a.jpg&quot; alt=&quot;West Wickham Bus Stop&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/3232330744/&quot; title=&quot;Julian outside the Tate Modern&quot;&gt;&lt;img src=&quot;https://farm4.static.flickr.com/3453/3232330744_3cabfc930f.jpg&quot; alt=&quot;Julian outside the Tate Modern&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;2006/7 — Abbey Road&lt;/h2&gt;
&lt;p&gt;I didn&apos;t take too many pictures while I was working at Abbey Road, but still kept up an interest. I mostly used my Lomo, but began to miss the control one gets with an SLR. I became rather disappointed with the expensive developing costs and the poor quality output from places like Jessops/Snappy Snaps/Boots — negatives would often be badly cut, have drying marks all over them, and scans would have some awful colour correction applied. I started scanning prints and negatives at home, with a relatively cheap scanner.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6210017741/&quot; title=&quot;District line, wooden floor&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6210/6210017741_2c16ab35f6.jpg&quot; alt=&quot;District line, wooden floor&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;In order to satisfy my need for a bit more control, I began to look into rangefinders, and received a Zorki 4K (a Leica replica) for Christmas. It&apos;s a purely mechanical camera, therefore repairable at home, but also prone to locking up. It did, however, come with a (highly sought after) Jupiter 8 lens. Here&apos;s some Abbey Road detail taken with that lens:&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205572358/&quot; title=&quot;Double basses, Abbey Road&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6168/6205572358_c6352d7ea9.jpg&quot; alt=&quot;Double basses, Abbey Road&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6205572480/&quot; title=&quot;Mic stands, Abbey Road&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6121/6205572480_92f46420d8.jpg&quot; alt=&quot;Mic stands, Abbey Road&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;2007/8  — Final Year, Uni&lt;/h2&gt;
&lt;p&gt;Just before starting my final year, I spent a week in Switzerland followed by a week camping on the Isle of Mull, Scotland, with the aim of taking photos and getting ideas for music. After Agfa went bust, and stopped producing (Jessops) slide film, I shot a lot more with regular colour film. Cross-processing slide film can be cool, but I think I prefer the feel of the regular stuff.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/1587828063/&quot; title=&quot;Forestry, Switzerland&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2205/1587828063_c2ec5e191a.jpg&quot; alt=&quot;Forestry, Switzerland&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;Photography in my final year at university focussed on evenings out and making music. I was listening to (and studying) a lot of glitchy electronic music, which partly explains my enjoyment of lo-fi photography and the Lomo. I looked into other lo-fi such as the JamCam (a cheap digital camera), as well as disposable cameras. The following is typical of the JamCam.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6222699706/&quot; title=&quot;Delay pedal&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6162/6222699706_88e1a66732.jpg&quot; alt=&quot;Delay pedal&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;I realised I hadn&apos;t captured many moments with my friends, so I made a start. As a result, I discovered how much I enjoy portraiture — not the staged kind, just moments.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/3228965314/&quot; title=&quot;Jordan at The End&quot;&gt;&lt;img src=&quot;https://farm4.static.flickr.com/3395/3228965314_4b3a5b0868.jpg&quot; alt=&quot;Jordan at The En&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;2008—10&lt;/h2&gt;
&lt;p&gt;After graduating I inherited a rather nice SLR from my Dad&apos;s work (unsurprisingly, they no longer use film to take pictures of microscopic slides). It came with a macro lens (which I&apos;ve yet to use) and so it wasn&apos;t until I bought a lens in Oxfam some time in 2010 that I considered using it (see New York pictures, below).&lt;/p&gt;
&lt;p&gt;I didn&apos;t feel particularly inspired to take pictures other than when I was on holiday or on special occasions. My &lt;a href=&quot;https://www.flickr.com/photos/helengavriel/&quot;&gt;lovely girlfriend&lt;/a&gt; and I visited Iceland and New York, where most my favourites from this time have come from.&lt;/p&gt;
&lt;p&gt;I also found a &lt;a href=&quot;https://www.westendcameras.co.uk&quot;&gt;great place to get film developed&lt;/a&gt;, where they actually look after your negatives!&lt;/p&gt;
&lt;h3&gt;Iceland &apos;09&lt;/h3&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/4129026960/&quot; title=&quot;Helen waiting for geysir to erupt&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2741/4129026960_ff137f76b1.jpg&quot; alt=&quot;Helen waiting for geysir to erupt&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/4129054416/&quot; title=&quot;Blue Lagoon, Iceland&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2601/4129054416_d100e46d36.jpg&quot; alt=&quot;Blue Lagoon, Iceland&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/4129054724/&quot; title=&quot;Icelandair wing&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2519/4129054724_33c64146a8.jpg&quot; alt=&quot;Icelandair wing&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h3&gt;New York &apos;10&lt;/h3&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/5711709730/&quot; title=&quot;Helen in New York&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2766/5711709730_88d2a82f01.jpg&quot; alt=&quot;Helen in New York&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/5711709454/&quot; title=&quot;Skyscrapers from Brooklyn Bridge&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2357/5711709454_7ec8e8630d.jpg&quot; alt=&quot;Skyscrapers from Brooklyn Bridge&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/6222882554/&quot; title=&quot;Schillers light bulb, New York&quot;&gt;&lt;img src=&quot;https://farm7.static.flickr.com/6051/6222882554_c925b98d32.jpg&quot; alt=&quot;Schillers light bulb, New York&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;Now&lt;/h2&gt;
&lt;p&gt;I&apos;d been looking get back into darkroom photography since university. I got so far as to ask in Jessops for some photographic chemicals. The assistant returned a clueless expression, which was rather disheartening (especially as I was job hunting at the time!).&lt;/p&gt;
&lt;p&gt;However, as has been the theme for much of the last ten years, I received some photographic equipment for Christmas last year, this time in the form of a changing bag and darkroom chemicals. I also inherited some developing trays and tanks from my uncle.&lt;/p&gt;
&lt;p&gt;So I&apos;m back into DIY black and white photography, and it feels great. I&apos;ve only developed a few rolls, and with every one I&apos;ve got stupidly nervous about the whole process. But I like that.&lt;/p&gt;
&lt;p&gt;I still haven&apos;t got the space to fit my enlarger(s) but I&apos;ve bought a decent flatbed scanner that does the job nicely.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/5807232165/&quot; title=&quot;James, Fortess Studios, London&quot;&gt;&lt;img src=&quot;https://farm3.static.flickr.com/2461/5807232165_e69cd489fc.jpg&quot; alt=&quot;James, Fortess Studios, London&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/5848681884/&quot; title=&quot;My Camper boots&quot;&gt;&lt;img src=&quot;https://farm6.static.flickr.com/5268/5848681884_32cc40537e.jpg&quot; alt=&quot;My Camper boots&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;I feel a bit more inspired to go and take photos of anything, now, though still not as much as I&apos;d like to. I always carry my Lomo or my Olympus mju II — another bargain from a charity shop.&lt;/p&gt;
&lt;figure&gt;&lt;a href=&quot;https://www.flickr.com/photos/domchristie/5711709262/&quot; title=&quot;Traffic cone busker&quot;&gt;&lt;img src=&quot;https://farm4.static.flickr.com/3608/5711709262_19abcce115.jpg&quot; alt=&quot;Traffic cone busker&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;I like to think I&apos;ll continue taking pictures on film and have the means to do so in the future, simply because I enjoy the process so much. I don&apos;t see my equipment changing much — I have quite enough cameras! Hopefully I&apos;ll set up a proper darkroom someday, and get printing again. That&apos;d be nice.&lt;/p&gt;
&lt;h2&gt;Photogeekery&lt;/h2&gt;
&lt;h3&gt;Cameras&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Lomo LC-A&lt;/li&gt;
  &lt;li&gt;Olympus OM-2n&lt;/li&gt;
  &lt;li&gt;Olympus mju II&lt;/li&gt;
  &lt;li&gt;Olympus AF-1&lt;/li&gt;
  &lt;li&gt;Voigtlander Bessa-R&lt;/li&gt;
  &lt;li&gt;Zorki 4K&lt;/li&gt;
  &lt;li&gt;Canon Powershot A85 (4.0MP)&lt;/li&gt;
  &lt;li&gt;JamCam&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Lenses&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Olympus OM-System 50mm f1.8&lt;/li&gt;
  &lt;li&gt;Jupiter 8 50mm f2&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Misc.&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Epson Perfection V700 Photo Scanner&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Mon, 10 Oct 2011 11:57:55 GMT</pubDate></item><item><title>iOS Placeholder &amp; Juration</title><link>https://domchristie.co.uk/posts/ios-placeholder-juration/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/ios-placeholder-juration/</guid><description>&lt;p&gt;I&apos;ve been pretty busy recently on a couple of small projects. As the name suggests, &lt;a href=&quot;https://github.com/domchristie/ios-placeholder&quot;&gt;iOS Placeholder&lt;/a&gt; is a jQuery plugin that emulates the iOS behaviour of placeholder text in the browser. It&apos;s inspired by Robert Nyman&apos;s ideas &lt;a href=&quot;https://robertnyman.com/2011/05/02/html5-placeholder-and-an-alternative-approach-introducing-roberts-playground/&quot;&gt;on placeholder text behaviour&lt;/a&gt;, and offers clearer labelling of input fields once they are in focus.&lt;/p&gt;
&lt;p&gt;The second project, &lt;a href=&quot;https://github.com/domchristie/juration&quot;&gt;Juration&lt;/a&gt;, is a simple time range parser/humanizer, inspired by the &lt;a href=&quot;https://github.com/mojombo/chronic/&quot;&gt;chronic&lt;/a&gt; and &lt;a href=&quot;https://github.com/hpoydar/chronic_duration&quot;&gt;chronic_duration&lt;/a&gt; Ruby gems. Parsing takes a duration in words (e.g. 3mins 50secs) and returns that value in seconds. Stringifying does the inverse - taking a value in seconds and converting it to words. Feel free to have a play on the &lt;a href=&quot;https://domchristie.github.com/juration&quot;&gt;Juration demo page&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 29 Sep 2011 07:16:02 GMT</pubDate></item><item><title>The WWWonderful Unstable Medium</title><link>https://domchristie.co.uk/posts/the-wwwonderful-unstable-medium/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/the-wwwonderful-unstable-medium/</guid><description>&lt;blockquote&gt;&lt;p&gt;Print is a wonderful stable medium, and turns out the web is a wonderful unstable medium&lt;/p&gt;
&lt;cite&gt;&lt;a href=&quot;https://vimeo.com/7556911&quot;&gt;David Berlow&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;
&lt;p&gt;Plenty has been written about the web as a flexible (or &apos;unstable&apos;) platform, but I thought I&apos;d collect my thoughts anyway.&lt;/p&gt;
&lt;p&gt;Despite being written over 10 years ago, John Allsopp&apos;s &lt;a href=&quot;https://www.alistapart.com/articles/dao/&quot;&gt;A Dao of Web Design&lt;/a&gt; couldn&apos;t be more relevant today, and is a great starting point. It&apos;s well worth a read, but I&apos;ll summarise.&lt;/p&gt;
&lt;p&gt;It basically encourages web designers to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Recognise the strengths of print design, but &lt;strong&gt;treat the web as its own platform&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Abandon control of &apos;the page&apos;&lt;/strong&gt; - embrace the lack of physical constraints and see it as an advantage&lt;/li&gt;
  &lt;li&gt;Create &lt;strong&gt;adaptable, accessible experiences&lt;/strong&gt; that best make use of the web&apos;s characteristics&lt;/li&gt;
  &lt;li&gt;Consider function over form&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inspiring stuff.&lt;/p&gt;
&lt;p&gt;Of course, many of these ideas are can also be applied to software design, and I&apos;m reminded of Apple and their latest software interfaces, notably iCal for OS X Lion and iPad apps such as Notes (pictured below) or iBooks. Feelings begin with, &quot;oOo, nice details!&quot;; then move on to, &quot;it&apos;s quite &apos;noisy&apos; and a bit distracting&quot;; to &quot;why am I pressing a button embedded in leather?&quot;.&lt;/p&gt;
&lt;img src=&quot;https://s3-eu-west-1.amazonaws.com/domchristie/ipad-notes.png&quot; alt=&quot;iPad Notes screenshot&quot;&gt;
&lt;p&gt;In his &lt;a href=&quot;https://arstechnica.com/apple/reviews/2011/07/mac-os-x-10-7.ars/5#crazy-ones&quot;&gt;OS X Lion review&lt;/a&gt;, John Siracusa picks up on this, pointing out the disparity between the look of interface and the way it behaves i.e. although it may look like you can tear off pages, and scribble in the margins...you can&apos;t. It&apos;s just interface noise.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Perfection [in design] is achieved not when there is nothing more to add, but rather when there is nothing more to take away.&lt;/p&gt;
&lt;cite&gt;Antoine de Saint-Exupéry&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, that&apos;s not to say that we should be creating totally flat interfaces. I think it&apos;s a balance between minimalism and rich UI - go too far in the minimal direction, and you may end up creating a bland user experience; too far in the other direction, and you could end up with noise that doesn&apos;t make much sense.&lt;/p&gt;
&lt;p&gt;Software allows us to do crazy things (like plonking buttons in leather), but simply replicating physical objects in a software interface, I feel, isn&apos;t particularly imaginative. Think of how far the boundaries could be pushed if the time spent perfecting iCal&apos;s faux-leather stitching, was instead spent on rethinking the calendar or how we could better organise our time&lt;sup&gt;&lt;a href=&quot;#fn3.1&quot; id=&quot;r3.1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Despite Apple taking the direction they have, there&apos;s definitely been a move in the web community to explore the capabilities of this unfixed platform. Just check out some of the &lt;a href=&quot;https://webdesignledger.com/inspiration/21-examples-of-parallax-scrolling-in-web-design&quot;&gt;examples of parallax scrolling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;d love to see more examples of web design that gets this concept spot on. If you have any in mind, &lt;a href=&quot;https://twitter.com/domchristie&quot;&gt;tweet at me&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some resources/more thoughts:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.alistapart.com/articles/responsive-web-design/&quot;&gt;Responsive Web Design&lt;/a&gt; by Ethan Marcotte; and &lt;a href=&quot;https://www.abookapart.com/products/responsive-web-design&quot;&gt;his book&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://focuslabllc.com/blog/what-the-fluff&quot;&gt;What the fluff&lt;/a&gt; - a nice article emphasising the importance of clarity in design&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.3quarksdaily.com/3quarksdaily/2011/02/against-chrome-a-manifesto.html&quot;&gt;Against Chrome: a Manifesto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section class=&quot;footnotes&quot;&gt;
  &lt;p id=&quot;fn3.1&quot;&gt;&lt;a href=&quot;#r3.1&quot;&gt;[1]&lt;/a&gt; maybe the calendar doesn&apos;t need a total rethink, but you get what I mean.&lt;/p&gt;
&lt;/section&gt;</description><pubDate>Thu, 18 Aug 2011 21:19:00 GMT</pubDate></item><item><title>A Simple Website on Rails?</title><link>https://domchristie.co.uk/posts/a-simple-website-on-rails/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/a-simple-website-on-rails/</guid><description>&lt;p&gt;Ever since I started using Rails, Git and Heroku, I&apos;ve been looking for a way to use these tools to create basic websites that have a nice interface for managing content.&lt;/p&gt;
&lt;p&gt;I&apos;d normally approach this kind of site with Wordpress. I like it&apos;s easy installation and the features it has out of the box; but getting it setup with Git and keeping development/production environments in sync (+ deployment) is a bit of a headache&lt;sup&gt;&lt;a href=&quot;#fn2.1&quot; id=&quot;r2.1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;What&apos;s more, as with most content management systems I&apos;ve used, I&apos;ve often found myself using ugly fixes to force it do do what I want it to, or trawling through directories to find a plugin that&apos;s sure not to break when I upgrade the CMS.&lt;/p&gt;
&lt;p&gt;I&apos;ve briefly looked into &lt;a href=&quot;http://radiantcms.org/&quot;&gt;Radiant&lt;/a&gt; and &lt;a href=&quot;http://refinerycms.com/&quot;&gt;Refinery&lt;/a&gt;: Rails-based alternatives that work fine within a Git workflow; but while they maybe easy to learn, I&apos;d rather be getting to know Rails better, rather than the particular workings of a CMS (I know, this sounds lazy!).&lt;/p&gt;
&lt;p&gt;The best solution I&apos;ve come across so far is &lt;a href=&quot;https://github.com/sferik/rails_admin&quot;&gt;Rails Admin&lt;/a&gt;, which, as the name implies, provides a simple way to administer content on a Rails backend. Although I&apos;ve only just started using it, it appears to have just the bare minimum features necessary to create/update content - allowing me to make the decisions about how my data is organised.&lt;/p&gt;
&lt;p&gt;Installation is easy and getting something up and running couldn&apos;t be quicker. This is probably because I work more with Ruby/Rails than I do with php/Wordpress (or any other CMS); but it suits me - particularly as I can focus on creating web apps with Rails and learning Ruby (a bit nicer than php, in my humble opinion!)&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
  &lt;p id=&quot;fn2.1&quot;&gt;&lt;a href=&quot;#r2.1&quot;&gt;[1]&lt;/a&gt; For example, it&apos;s all too easy modify files outside of the Git workflow - what with the ability to update the CMS via the Wordpress interface.&lt;/p&gt;
&lt;/section&gt;</description><pubDate>Sat, 06 Aug 2011 21:26:00 GMT</pubDate></item><item><title>Hello World</title><link>https://domchristie.co.uk/posts/hello-world/</link><guid isPermaLink="true">https://domchristie.co.uk/posts/hello-world/</guid><description>&lt;p&gt;I had a reputation at university for being rather slow at writing essays. I&apos;d labour over every sentence, making sure it was clear and concise and the best it could possibly be before moving on to the next one. As you can imagine, when you&apos;ve got thousands of words to write, this process doesn&apos;t work very well.&lt;/p&gt;
&lt;p&gt;This attention to detail still manifests itself in the work I do everyday, and it can be painful (believe it or not, this sentence is the product of many iterations!); but I have some thoughts, and bizarrely enough, I miss writing them down. So I will start.&lt;/p&gt;
&lt;p&gt;That&apos;s all for now, though. It&apos;s taken me long enough.&lt;/p&gt;</description><pubDate>Mon, 01 Aug 2011 07:03:00 GMT</pubDate></item></channel></rss>