<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Kris Jenkins&apos; Blog</title><description>The personal blog of Kris Jenkins, geek.</description><link>https://blog.jenkster.com/</link><language>en-gb</language><item><title>Why fsyncing a File Isn&apos;t Safe Enough</title><link>https://blog.jenkster.com/2026/09/fsync-file-safety.html</link><guid isPermaLink="true">https://blog.jenkster.com/2026/09/fsync-file-safety.html</guid><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I learnt something interesting about writing files to disk. Something that connects &lt;a href=&quot;https://github.com/clockworklabs/SpacetimeDB/pull/5785&quot;&gt;my first ever low-level database PR&lt;/a&gt; with the reason you can’t pull a USB disk out of your laptop without ejecting it first.&lt;/p&gt;
&lt;p&gt;As you may know, when you write a file on a computer it doesn’t actually get written to the disk straight away. In reality it gets written into some cache in memory, with a promise that the information will be permanently stored on disk “soon”. It’s the operating system’s job to fulfil that promise. To prioritise getting your data safely stored on disk along with the dozens of other tasks it’s trying to do at the same time. Usually that’s quite fast, but it depends on a lot of factors. In practice, writing to disk “soon” may mean milliseconds or minutes.&lt;/p&gt;
&lt;p&gt;There is a risk to that though. What if you save your file, then the machine immediately crashes? Was the file saved to disk in time, or was it still only in memory? Does a crashed operating system mean lost data?&lt;/p&gt;
&lt;p&gt;The answer depends on &lt;code&gt;fsync&lt;/code&gt;. Now this part I’ve known for years - if you want to write a file to disk, and actually be certain it’s on the disk, you have to &lt;code&gt;fsync&lt;/code&gt; it. You have to tell the operating system that you want your data written, and you want to wait until it’s actually guaranteed on-disk. To do that, you write the data then call &lt;code&gt;fsync&lt;/code&gt;. When &lt;code&gt;fsync&lt;/code&gt; returns, the OS has completed its promise and your data is durable.&lt;/p&gt;
&lt;p&gt;Databases use &lt;code&gt;fsync&lt;/code&gt; all the time to make sure data is permanent. It’s also why you can’t pull out a USB disk without pressing eject first. The eject button is the user-facing version of &lt;code&gt;fsync&lt;/code&gt; - it makes sure that everything you &lt;em&gt;think&lt;/em&gt; you wrote to the disk is actually physically stored before you disconnect it.&lt;/p&gt;
&lt;p&gt;But here’s the thing I didn’t know about &lt;code&gt;fsync&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-hindsight&quot; id=&quot;user-content-fnref-hindsight&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. If you call &lt;code&gt;fsync&lt;/code&gt; on a file, it only makes the contents of the file permanent - not the things that file depends on. So imagine this scenario:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new file.&lt;/li&gt;
&lt;li&gt;Write some data to it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fsync&lt;/code&gt; the file.&lt;/li&gt;
&lt;li&gt;The computer crashes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What happens? In the worst-case scenario you’ve lost your data, even though you fsync’d it! &lt;strong&gt;The file itself was written permanently, but the new directory entry pointing to the file was not.&lt;/strong&gt; So the data’s on disk as promised, but there’s no way to access it. You can’t see the new file entry in the directory. A forensic specialist could track the data down, but you and I have lost the route in. And that’s the important thing I learnt: &lt;code&gt;fsync&lt;/code&gt; doesn’t save all your work to disk. If you modified the parent directory by creating a new file, you have to &lt;code&gt;fsync&lt;/code&gt; the parent too.&lt;/p&gt;
&lt;p&gt;Doubtless the writers of the USB disk’s eject button knew this. I learnt it while I was looking through the code of &lt;a href=&quot;https://spacetimedb.com/?referral=krisajenkins&quot;&gt;SpacetimeDB&lt;/a&gt;. There’s a case where it’s building up the database’s write log, and it has to create a new segment file. The code correctly fsync’d the file, but not the parent directory. An unlucky crash could have led to data loss. Of course, it’s an easy fix - you just make the extra &lt;code&gt;fsync&lt;/code&gt; call. I patched it and it got released this week in &lt;a href=&quot;https://github.com/clockworklabs/SpacetimeDB/releases/tag/v2.9.0&quot;&gt;v2.9.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And that small-but-important improvement is my first truly low-level database contribution. Never have I patched so close to the hardware before. 😊&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-hindsight&quot;&gt;
&lt;p&gt;Perhaps I should have known. Perhaps when I first learnt about &lt;code&gt;fsync&lt;/code&gt; it worked differently. Certainly there are some filesystem configurations where a single &lt;code&gt;fsync&lt;/code&gt; is enough. But no one wants to leave these things to chance. &lt;a href=&quot;#user-content-fnref-hindsight&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Vibe Management</title><link>https://blog.jenkster.com/2026/06/vibe-management.html</link><guid isPermaLink="true">https://blog.jenkster.com/2026/06/vibe-management.html</guid><pubDate>Mon, 22 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Lots of people are worried about Vibe Coding, and rightly so, but the thing that worries me far more is Vibe Management.&lt;/p&gt;
&lt;p&gt;Vibe Management goes like this: Someone in middle management is told to come up with a strategy document for the next quarter. That sounds like an awful lot of work, so they start feeding documents into Claude. They tell themselves they’re getting AI to “do the first pass”, but the reality is Claude’s first pass comes out looking pretty good, and thinking of something better would be hard work, so they copy &amp;amp; paste the output into Google Docs. They change the odd sentence here and there, sure. Tell themselves they’re polishing the result. But pretty soon they call it a day. The strategy document has been created, the box has been ticked.&lt;/p&gt;
&lt;p&gt;Has the strategy had any thought put into it? Don’t ask difficult questions! A document was asked for, a document has been written, and it’s filled with strategy words like ‘objective’ and ‘leverage’. What more do you want?&lt;/p&gt;
&lt;p&gt;Document complete, they send it to their boss, who’s receiving similar documents from 5-50 other direct reports. Reviewing all those sounds like an awful lot of work, so they too shove it into Claude - thank God for that 1M-token context window - and Claude synthesises all those hallucinated strategies into an uber-hallucination they can pass up the chain. Claude will also write some comments on each source-document, feedback which will also be read by Claude. The digital echo chamber reaches perfection.&lt;/p&gt;
&lt;p&gt;We now have a whole middle-management layer of strategies that have never had time, thought or effort put into them. At no point have they observed reality. At no point have they sought insight. But you can be sure of two things - there will be lots &amp;amp; lots of Google Docs to back the ‘strategy’ up, and the people on the front line will be expected to execute this ‘strategy’ no matter how detached from reality it may be.&lt;/p&gt;
&lt;p&gt;We are in an age where making something that seems fine has never been easier. You want a website that seems to work? I can turn it around in an hour. You want a Q3 strategy that seems smart? I can crank that out while I get coffee. But the reason the website worries me less is, if it doesn’t work you’ll probably find out pretty soon. The feedback loop for Vibe Coding bugs is usually measured in days, and usually not that expensive. But the feedback loop for Vibe Management is measured in quarters, and three or four quarters spent pursuing the wrong strategy can sink a company. We’re going to see companies spend a year, and a department’s worth of salaries, trying to execute on a strategy that never had an ounce of thought put into it. And it’s going to do damage to vastly more people than the managers who were looking for a shortcut.&lt;/p&gt;
&lt;p&gt;In the end, Vibe Coding and Vibe Management are symptoms of the same problem - letting AI do all your thinking for you. But for the most part, Vibe Management has a vastly larger org chart to inflict its damage on.&lt;/p&gt;
</content:encoded></item><item><title>The AI Bubble Will And Won&apos;t Burst</title><link>https://blog.jenkster.com/2026/03/ai-bubble-burst.html</link><guid isPermaLink="true">https://blog.jenkster.com/2026/03/ai-bubble-burst.html</guid><pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m going to record this prediction now so that it can warm me in the winter months: The AI bubble will burst &lt;em&gt;and&lt;/em&gt; the AI bubble will not burst.&lt;/p&gt;
&lt;p&gt;The AI bubble will burst. I predict that because I’ve seen it in hype cycles ever since the dot-com era. Astonishing sums of money get spent building infrastructure for massively overvalued companies, and the profits just aren’t there to support it. Later, when the fickle winds of the markets change, the companies that paid for all that infrastructure collapse. But the infrastructure remains. The GPU farms exist now and they’ll still exist when the bubble bursts; they’ll just move to a clean-slate balance sheet. The financial circle of life continues. As long as you weren’t invested in those companies, it’s probably a good thing - you get to benefit from the roads someone else built and paid for.&lt;/p&gt;
&lt;p&gt;Meanwhile, the AI bubble will not burst. Financial shenanigans aside, AI is here to stay. Who owns the models, who trained the models, which computers they run on — that’s a shell game that’s going to be played for a few years yet. But the technology itself? That’s here to stay. It’s changed things in a way that’s not going to be undone. Shut down Claude and half the people I know will just write spec files until it’s back up. Pandora’s box is open.&lt;/p&gt;
&lt;p&gt;In short, I predict AI will sink &lt;em&gt;and&lt;/em&gt; swim. Since the combustion engine rocked the world, the car makers changed, fortunes rose and fell, but none of it sent us back to riding horses.&lt;/p&gt;
</content:encoded></item><item><title>The Shelf Life of an AI Study Is About Six Months</title><link>https://blog.jenkster.com/2026/02/ai-study-shelf-life.html</link><guid isPermaLink="true">https://blog.jenkster.com/2026/02/ai-study-shelf-life.html</guid><pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There’s a &lt;a href=&quot;https://lnkd.in/euF9_SFR&quot;&gt;much-referenced study&lt;/a&gt; that says if you’re using LLMs for programming, you only think it’s making you faster. Programmers claim they’re more productive with AI tools, but when studied they actually take longer to get the job done. It’s a proper report — all the hard facts you’d need to justify a long discussion of AI hype &amp;amp; AI slop, setting up an essay on why the author won’t be changing their habits any time soon.&lt;/p&gt;
&lt;p&gt;But there’s a massive problem with that study — it’s ancient. The sample data was gathered in early 2025. A year can be a long time in technology, but this particular year the AI world has moved at a staggering pace. Last winter, AI coding tools felt like very fancy autocomplete — they worked well provided your problem had already been roughly answered on StackOverflow. Today, they tackle difficult, multi-commit changes to large codebases fully autonomously, while you check your email. As I write this, I have one agent migrating an Obsidian plugin to Svelte 5 and another researching networking models from the early 2000s&lt;sup&gt;&lt;a href=&quot;#user-content-fn-ben&quot; id=&quot;user-content-fnref-ben&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. I’ll check in on them both later, while an agent proofreads this post for me. You simply can’t talk about AI in February 2026 by referencing a study from February 2025. They’re twelve months and a lifetime apart.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong — objectively studying these models is important, valuable research. But at this stage, citing “Becker et al. says AI makes you 19% slower” isn’t a counter-argument. It’s a history essay.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-ben&quot;&gt;
&lt;p&gt;Don’t ask why, but it’s Ben Gamble’s fault. &lt;a href=&quot;#user-content-fnref-ben&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Making Your Agent See What It&apos;s Missing</title><link>https://blog.jenkster.com/2026/01/making-your-agent-see-what-its-missing.html</link><guid isPermaLink="true">https://blog.jenkster.com/2026/01/making-your-agent-see-what-its-missing.html</guid><pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Coding agents like Claude or Warp are pretty good at basic web design. Nowhere near as good as a graphic designer, but honestly much better at graphic design than an average programmer. With a bit of nudging I can get results in ten minutes that are &lt;em&gt;at least&lt;/em&gt; as good as I could manage after several hours of sweating through CSS files. But only if they have a good feedback loop.&lt;/p&gt;
&lt;p&gt;The best tip I’ve discovered for turning them into a Minimum Viable Graphic Designer, is you want to teach them how to take screenshots. Remember, coding agents are only as good as the feedback they can gather. They become better programmers when you give them a compiler or a test suite, because they can see where they’ve gone wrong. And they become better designers when they can see what impact the changes had on the way the page renders.&lt;/p&gt;
&lt;p&gt;So my top tip for working with AI and websites is, teach them how to take screenshots and insist they do! For this, I usually put a rule in the project along the lines of:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;markdown&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;You can take screenshots of a webpage with &lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;`playwright screenshot --full-page $URL $OUTPUT_FILE`&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;. For example:&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:#50FA7B&quot;&gt;```bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;playwright&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; screenshot&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; --full-page&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; http://localhost:8000&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; screenshot.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&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:#F8F8F2&quot;&gt;You must take a screenshot whenever you&apos;re finished making design changes. Take the screenshot and check it looks good, and matches what the user asked for.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(You’ll need to &lt;a href=&quot;https://playwright.dev/docs/intro#installing-playwright&quot;&gt;have Playwright installed&lt;/a&gt; of course.)&lt;/p&gt;
&lt;p&gt;It’s a pretty simple instruction. The key is, it enables a feedback loop, and feedback loops make all the difference in the world.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Fun parting tip: You can also say, “Make it look like Apple’s website,” for example. With the ability to make screenshots, it can actually look at Apple’s website and use it as a design reference.&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>Configuring Neovim &amp; Nix to use Java&apos;s LSP Server</title><link>https://blog.jenkster.com/2025/06/neovim-lsp-and-nix.html</link><guid isPermaLink="true">https://blog.jenkster.com/2025/06/neovim-lsp-and-nix.html</guid><pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve had some problems setting up an LSP server with &lt;a href=&quot;https://neovim.io/&quot;&gt;Neovim&lt;/a&gt;. I think maybe some of my problems came from path clashes with &lt;a href=&quot;https://nixos.org/&quot;&gt;nix&lt;/a&gt;. Now I’ve got it working, here’s a note of the config.&lt;/p&gt;
&lt;p&gt;Hopefully it will help some future visitor, and there’s a very good chance one of those future visitors is me. 😅&lt;/p&gt;
&lt;h2 id=&quot;neovims-lsp-config&quot;&gt;Neovim’s LSP Config&lt;/h2&gt;
&lt;p&gt;I’m using the &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;lspconfig&lt;/a&gt; project. Here’s the Java-specific part of the config:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;lua&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;lspconfig.jdtls.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;setup&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    cmd &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &apos;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;nix&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &apos;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;develop&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &apos;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;--command&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &apos;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;jdtls&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;    init_options &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        settings &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            java &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                imports &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    gradle &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        enabled &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        wrapper &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                            enabled &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;                            -- Note the nested table here. This is really important.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;                            -- `checksums` is an array of objects, which in lua translates to a table of tables.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                            checksums &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                    sha256 &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;7d3a4ac4de1c32b59bc6a4eb8ecb8e612ccd0cf1ae1e99f66902da64df296172&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                    allowed &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the &lt;code&gt;cmd&lt;/code&gt; is running &lt;code&gt;jdtls&lt;/code&gt; through nix. Also note that the SHA256 may need updating depending on which versions of everything you’re using. The &lt;a href=&quot;https://github.com/eclipse-jdtls/eclipse.jdt.ls&quot;&gt;jdtls&lt;/a&gt; is Eclipse’s Java language server.&lt;/p&gt;
&lt;h2 id=&quot;nixs-flakenix&quot;&gt;Nix’s &lt;code&gt;flake.nix&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;nix&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;  inputs&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;    nixpkgs&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; &quot;github:NixOS/nixpkgs/25.05&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;    utils&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; &quot;github:numtide/flake-utils&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&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:#50FA7B;font-style:italic&quot;&gt;  outputs&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt; nixpkgs&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt; utils&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; }:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;    utils&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;eachDefaultSystem&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;system&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;      let&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;        pkgs&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt; nixpkgs&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;          inherit&lt;/span&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt; system&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;          overlays&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [ ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;      in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;        devShell&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;          with&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt; pkgs&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;          mkShell&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B;font-style:italic&quot;&gt;            buildInputs&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;              jdk21&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;              jdt-language-server&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:#F8F8F2&quot;&gt;              (&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;writeShellScriptBin&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; &quot;run&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;                set -e&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;                ./gradlew bootRun&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;              &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&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:#50FA7B;font-style:italic&quot;&gt;            JAVA_HOME&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt; jdk21&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The &lt;code&gt;writeShellScriptBin&lt;/code&gt; part isn’t necessary for this, but I’m leaving it in
because it might be an interesting bonus tip.)&lt;/p&gt;
&lt;h2 id=&quot;gradles-buildgradlekts&quot;&gt;Gradle’s &lt;code&gt;build.gradle.kts&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Getting the JDK versions to agree between &lt;a href=&quot;https://nixos.org/&quot;&gt;Nix&lt;/a&gt; and &lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt; is important:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;kotlin&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#50FA7B&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;	toolchain&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;		languageVersion &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; JavaLanguageVersion.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;21&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content:encoded></item><item><title>Delegated Coding Has A Bright Future</title><link>https://blog.jenkster.com/2025/06/delegated_coding.html</link><guid isPermaLink="true">https://blog.jenkster.com/2025/06/delegated_coding.html</guid><pubDate>Tue, 10 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s a shame the term “Vibe Coding” got big, and triggered a wave of hype &amp;amp; counter-cynicism. It’s just muddied the water.&lt;/p&gt;
&lt;p&gt;The way I see it, Agentic AI is going to be a lot like having a team of junior programmers. Programmers that lack deep roots but are great researchers; that work incredibly hard but lose sight of the big picture.&lt;/p&gt;
&lt;p&gt;So the people best placed to take advantage of it aren’t those who know less about programming than a junior. It’s those who understand how to architect a cohesive whole, who are good at managing a team of juniors and great at breaking down features small enough to hand off to that team. To those who see the features that matter, break them down and delegate them, and those who see architectural problems on the horizon and delegate the work needed to avoid them. (And to those who understand why version control matters. 😁)&lt;/p&gt;
&lt;p&gt;Vibe Coding’s going to create a lot of slop that only &lt;em&gt;seems&lt;/em&gt; to work, but Delegated Coding’s going to standing up more quality services than we’ve ever seen before. It’s an exciting time.&lt;/p&gt;
</content:encoded></item><item><title>Tustain&apos;s Law</title><link>https://blog.jenkster.com/2025/05/tustains-law.html</link><guid isPermaLink="true">https://blog.jenkster.com/2025/05/tustains-law.html</guid><pubDate>Sun, 18 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I’ve been thinking about something I affectionately call Tustain’s Law. It’s something a friend of mine was fond of saying: “If you make something twice as easy, it becomes ten times more useful.”&lt;/p&gt;
&lt;p&gt;You can argue the numbers of course, but the insight is clear - making something easier to use doesn’t just mean your users will have a nicer time; often it means that ten people are trying to engage with what you’ve built, and nine of them will give up in frustration unless you’re actively designing with them in mind.&lt;/p&gt;
&lt;p&gt;Ten times more useful reminds me of the first pair of Bluetooth headphones I owned. They always had connection problems. It was rare they’d connect first time, and because they were unreliable I didn’t get much value out of them. The headphones I own today are functionally identical objects - similar sound quality, similar battery life - but because they always work they slip into my unconscious and have become a permanent part of my life. I use them for at least 40 hours a week and I don’t leave the house without them.&lt;/p&gt;
&lt;p&gt;Tustain’s Law means user-friendliness isn’t just a nice-to-have. It’s not a luxury to be tacked on if there’s time at the end of the sprint. It’s actually fundamental to how valuable what you make becomes. It changes the way people engage with technology, moving it from “if I really have no choice” to “it’s my go-to tool”. In many cases, “10x more useful” would be a conservative estimate - it’s probably closer to infinitely more useful. The difference between using it or not.&lt;/p&gt;
&lt;p&gt;Paul Tustain, the man behind Tustain’s Law, was killed last week in a tragic motorbike accident. He was a brilliant man, easily the smartest CEO I’ve ever known, and a good friend who profoundly changed the course of my life.&lt;/p&gt;
&lt;p&gt;Maybe in the coming days I’ll face writing up a proper obituary or something, but for now this is all I can manage. And it’s a pretty good start - if you’re following me you’re probably into technology, and knowing Tustain’s Law might help you make what you’re working on ten times more useful to people. That might help you change the world, or at least your corner of it. And if it does, then Paul has had a profound effect on your life too…&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Paul Tustain, 1962-2025. Rest In Peace my friend.&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>Why We Podcast</title><link>https://blog.jenkster.com/2023/04/why-we-podcast.html</link><guid isPermaLink="true">https://blog.jenkster.com/2023/04/why-we-podcast.html</guid><pubDate>Tue, 11 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve just come to the end of my year-and-a-bit stint as the host of
the Streaming Audio podcast, so I thought I’d take a moment to reflect
on podcasting. What’s in it for the listener, the guest, the host and
the company?&lt;/p&gt;
&lt;p&gt;Over the past year, I got to record conversations with over 70 guests
about their patch of the technology landscape, and what a privilege it
was. There was a lot of work behind the scenes to make it
happen. There were many, many hours of pacing back and forth
muttering, “Yes, but what’s the &lt;em&gt;story&lt;/em&gt; here?” And there was far more
calendar juggling than I’ll ever be comfortable with. But every single
time I hit the record button it became a joy. Talking with &lt;em&gt;my kind of
people&lt;/em&gt;, listening to them, and getting a glimpse into their minds and
their problems. Learning.&lt;/p&gt;
&lt;p&gt;So whether you’re a potential host, a future guest, or a company
thinking of starting a podcast, here are my thoughts on what it takes,
why we do it, and why it turned out to be one of the most valuable
parts of my career so far.&lt;/p&gt;
&lt;h2 id=&quot;lets-start-with-the-business-case&quot;&gt;Let’s Start With The Business Case&lt;/h2&gt;
&lt;p&gt;I was invited on &lt;a href=&quot;https://podcasts.mongodb.com/public/115/The-MongoDB-Podcast-b02cf624/55dbf587&quot;&gt;the MongoDB podcast last year&lt;/a&gt; for
International Podcast Day, and one of the questions that came up was,
“Why would your company want to run a podcast?” Sure, it’s nice to
have a chat and all, but is there a compelling reason for your company
to pay you to put all those hours in? I don’t think the answer to that
had quite crystallised in my mind back then, but it has now. In
hindsight, podcasting was probably the most effective piece of
Developer Advocacy I did, because it goes to the heart of what I think
Developer Relations is all about.&lt;/p&gt;
&lt;h3 id=&quot;a-tech-company-must-talk-to-developers-not-at-them&quot;&gt;A Tech Company Must Talk To Developers (Not At Them)&lt;/h3&gt;
&lt;p&gt;This is true of any company whose users are technical, but absolutely
fundamental to a company that makes tools for developers. You can’t
just build it and throw it over the wall. You have to be talking,
teaching, learning and listening to the developers you hope to
serve. You need a healthy feedback loop to create a product that’s
always improving and a community that’s always growing.&lt;/p&gt;
&lt;p&gt;To my mind, Developer Advocacy is simply making that conversation an
official priority. Just as you have a department that prioritises
finance or infrastructure, you have people dedicated to building and
caring for the ongoing conversation with developers.&lt;/p&gt;
&lt;p&gt;But how?&lt;/p&gt;
&lt;p&gt;We know the default answers. Forums and Slack channels are great if
you can build up enough momentum to be somewhat
self-supporting. Conference talks and workshops are perfect for
high-quality interactions, but you have to travel far and wide if you
want to reach all the different enclaves. Blog posts are great,
broad-reach content, but even the best writers I know would struggle
to write more than a couple of non-trivial posts&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; a month.&lt;/p&gt;
&lt;p&gt;Podcasts are another way to get involved in that developer
conversation, and they combine some of the best properties of the
usual formats. Like blog posts, they’ve got global reach and a long
tail. Like forums, they can help build and strengthen a sense of
community, especially as notable figures in that community appear as
guests and add their voices to the conversation. And like conferences,
podcasts are extremely high-quality interactions, having a personal,
meaningful conversation, and recording it in a format where everyone
can benefit. Done right, they have all the depth and value of a
one-on-one conversation, reshaped into a broadcast that thousands of
people can get value from. Human soul, with company-pleasing metrics.&lt;/p&gt;
&lt;p&gt;Okay, that’s the must-pay-the-bills angle, so on to…&lt;/p&gt;
&lt;h2 id=&quot;whats-in-it-for-the-listener&quot;&gt;What’s In It For The Listener?&lt;/h2&gt;
&lt;p&gt;As a host, you’re a proxy for the audience, so to me that meant going
into every conversation determined to learn something from the
guest. What’s interesting is how many different shapes that education
could take. Sometimes it meant asking technical questions about which
configuration parameters mattered. Sometimes business questions about
what this new feature buy me, and what will it cost me? And sometimes
it was personal questions that brought everything together. There was
&lt;a href=&quot;https://youtu.be/gCFciFkbR88&quot;&gt;a great episode with Rashmi Prabhu&lt;/a&gt; where we were talking
about the topic of managing banks of clusters of servers. It’s a
potentially dry topic, but halfway in I realised that this was 100%
her jam. The real story was how much she enjoyed solving these kinds
of problems, and once you see the problem through her eyes it
blossomed into a source of fascinating software puzzles. That,
perhaps, is the fundamental thing you can learn from a podcast with 52
different voices a year - 52 perspectives from which the world is
fascinating. 52 windows we can peer through and learn what they’ve
learned. Somewhere in there, there’s 52 miles’ worth of walking in
someone else’s shoes.&lt;/p&gt;
&lt;p&gt;And with all those shoes walking through our office, we should
probably ask…&lt;/p&gt;
&lt;h2 id=&quot;whats-in-it-for-the-guest&quot;&gt;What’s In It For The Guest?&lt;/h2&gt;
&lt;p&gt;The initial motivation overlaps with why people speak at conferences -
it’s that same urge to share knowledge. To share what you’ve learnt,
to make the road easier for the people that come after you, and to
maybe pick up some new friends along the way. It also never harms your
career to establish yourself as an expert&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; No one knows how much your
voice matters until you use it. Not even you.&lt;/p&gt;
&lt;p&gt;There are a couple of less obvious benefits too. One is that it’s a
lot easier to be a podcast guest than a conference speaker. Preparing
a conference talk involves a huge amount of writing, rehearing, travel
and nerves. Chatting to someone about your work is so easy you’re
probably already doing it regularly without thinking about it. Talks
can be hard, but conversation is something humans are hard-wired to
do. A good host sets you up to look good without even trying. 😎&lt;/p&gt;
&lt;p&gt;Another benefit—and one that truly surprised me—came from &lt;a href=&quot;https://youtu.be/kiF26OijJ-Y&quot;&gt;talking to
Dom Fioravanti about the company he was helping to grow&lt;/a&gt;. A
couple of months after the episode broadcast he told me it had been a
huge help in hiring and in getting investment. Telling your story in
such a casual, organic way can help investors to get a handle on a
technical subject, and can add valuable context and tone when you’re
talking to prospective employees. Conversations transmit in a way that
slide decks can’t.&lt;/p&gt;
&lt;p&gt;And of course, while I have no evidence for this, I hope a few authors
sold a few more copies of their book, and a few builders of valuable
services get a few new customers to value them. That kind of thing
never harms, does it?&lt;/p&gt;
&lt;p&gt;Okay, that’s everybody else covered, so I get to end by talking a
little about me. 😉&lt;/p&gt;
&lt;h2 id=&quot;whats-it-like-behind-the-mic&quot;&gt;What’s It Like Behind The Mic?&lt;/h2&gt;
&lt;p&gt;To a large degree, if there are great reasons for the audience and for
the company, that’s the case closed. Greenlight that podcast and away
we go. But as the host, you have to have more motivation than that. If
you want to do a good job, and do it every week of the year, you have
to know where the joy is and what the workload will be.&lt;/p&gt;
&lt;p&gt;The biggest thing I got from it was the chance to learn from
people. I’m not just a proxy for the audience - I’m the audience too!
And I got a front-row seat to learn from some of the best. I got to
pick the guests who sounded most interesting, and then direct the
conversation to whatever details I most wanted to learn. It was always
with the audience in mind, but I got to let my personal curiosity
drive.&lt;/p&gt;
&lt;p&gt;I also met some fascinating people along the way, from an &lt;a href=&quot;https://youtu.be/ChMWfGbunmM&quot;&gt;author of
technical books for children&lt;/a&gt; to &lt;a href=&quot;https://youtu.be/xlO3mRKrM_I&quot;&gt;the hosts of a podcast in
Hebrew&lt;/a&gt;; from &lt;a href=&quot;https://youtu.be/-Ug2RHYpMF4&quot;&gt;a sporting world I never thought I’d
explore&lt;/a&gt; to &lt;a href=&quot;https://youtu.be/odsNA9UUlUE&quot;&gt;a whole panel of experts contemplating the
future of how we architect information systems&lt;/a&gt;. I got to
travel to people, places and ideas, and take an audience with me for
the ride. (I also got to chat with friends and call it work. It was
work, but that didn’t stop it from being a pleasure too.)&lt;/p&gt;
&lt;p&gt;The hardest part of it for me was always off-camera. Every podcast was
preceded by a phase of assembling a scratchpad’s worth of notes,
figuring out how all those clues could fit together to form a cohesive
story, and then preparing enough that we could talk through that story
without it feeling scripted - having a roadmap without running on
rails. I always wanted it to feel like an organic conversation,
without it becoming a directionless ramble. That takes some prep.&lt;/p&gt;
&lt;p&gt;And the time after the conversation could be just as much work. How do
you take an hour’s worth of conversation and boil it down into a
2-minute intro? What did we actually end up talking about? Which parts
mattered most? How do you explain why it matters to an audience that
might be causally dropping in for the opening minutes? I learnt a heck
of a lot about storytelling and structure just from the relentless
need to meet a weekly cadence.&lt;/p&gt;
&lt;p&gt;The upside to that work was considerable. I got to pick the brains of
the best and brightest. I got the chance to follow my instincts and
say, “They interest me, so I’ll bet they’ll interest everyone else.”
And this one may sound strange, but I got the honour of sitting in
people’s cars and kitchens, on their trips to the gym and their dog
walks, every week. I’m a bit of an audiophile. Not the “gold-plated
hifi cables” kind, but I do get a great deal of pleasure from music,
audio and the spoken word. The fact that people selected me as a sound
they wanted to hear regularly brings me a great deal of pride, and
joy. If you were a listener, thank you. ❤️&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;You can get a long way on quick tips, listicles, and more prosaic versions of documentation, but writing with real depth takes time. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Some of your guests won’t consider themselves “experts”. Don’t let their modesty fool you. Some guests have literally written the book on a topic, while others have the battle scars from living with a tool in production. Both kinds of expertise are invaluable. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Setting Up A kcat Config</title><link>https://blog.jenkster.com/2022/10/setting-up-kcat-config.html</link><guid isPermaLink="true">https://blog.jenkster.com/2022/10/setting-up-kcat-config.html</guid><pubDate>Tue, 11 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’re using &lt;a href=&quot;https://kafka.apache.org/&quot;&gt;Kafka&lt;/a&gt;, &lt;a href=&quot;https://github.com/edenhill/kcat&quot;&gt;&lt;code&gt;kcat&lt;/code&gt;&lt;/a&gt; is an essential tool to have in your
toolbox. As the name suggests, it’s &lt;code&gt;cat&lt;/code&gt; for Kafka. It gives you
fast, command-line access to simple tasks. Like, say you want to tail
a topic called &lt;code&gt;orders&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;kcat&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -Ct&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; orders&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;(&lt;code&gt;-C&lt;/code&gt; is ‘consume’. &lt;code&gt;-t&lt;/code&gt; sets the topic name. This is unix, so you can collapse those flags into &lt;code&gt;-Ct&lt;/code&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Easy huh? Well, not quite. Because there’s usually more to type than that. For a local Kafka instance you need to set the broker:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;kcat&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -Ct&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; orders&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; localhost:9092&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s a pain. And if you want to access a remote machine it gets much worse:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;kcat&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -Ct&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; orders&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; localhost:9092&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -X&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; security.protocol=sasl_ssl&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -X&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; sasl.mechanism=PLAIN&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ...ugh...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But you don’t have to do that. You can put it all in a &lt;a href=&quot;https://github.com/edenhill/kcat#configuration&quot;&gt;&lt;code&gt;kcat&lt;/code&gt;
config&lt;/a&gt; file. It’s a little bit of a tricky one to
get right though, so for your reference and mine, here’s how you set
that up once and for all.&lt;/p&gt;
&lt;h2 id=&quot;example-kcat-config-files&quot;&gt;Example kcat Config Files&lt;/h2&gt;
&lt;p&gt;The file you need to edit is &lt;code&gt;~/.config/kcat.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For a local instance, it should contain something like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;metadata.broker.list=localhost:9092&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For a remote server, you’ll need to include the authentication details, so your &lt;code&gt;kcat.conf&lt;/code&gt; will look more like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;metadata.broker.list=&amp;lt;Bootstrap Server&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;security.protocol=sasl_ssl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sasl.mechanism=PLAIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sasl.username=&amp;lt;API Key&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sasl.password=&amp;lt;API Secret&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With a &lt;code&gt;kcat.conf&lt;/code&gt; correctly set up, all the connection information
gets picked up every time you call &lt;code&gt;kcat&lt;/code&gt;, so that first, simpler
command &lt;code&gt;kcat -Ct orders&lt;/code&gt; should Just Work.&lt;/p&gt;
&lt;h2 id=&quot;supporting-schema-registry&quot;&gt;Supporting Schema Registry&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; After I wrote this up I found myself wishing I could do the
same trick to connect to a Schema Registry. I’d like to be able decode
some Avro values by simply saying:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;kcat&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -Ct&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; orders&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; value=avro&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again, that’s not too hard. You “just” need to cram the location of
the schema registry, and your authentication details, in the right
format under the right key. Here’s the magic incantation to add to
your &lt;code&gt;~/.config/kcat.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;schema.registry.url=https://&amp;lt;SR API Key&amp;gt;:&amp;lt;SR API Key&amp;gt;@&amp;lt;SR URL&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that, &lt;code&gt;kcat&lt;/code&gt; will attempt to fetch schemas from the registry
whenever it needs a codec.&lt;/p&gt;
</content:encoded></item><item><title>MicroServices - Check Size Before Ordering</title><link>https://blog.jenkster.com/2018/07/microservices-check-size.html</link><guid isPermaLink="true">https://blog.jenkster.com/2018/07/microservices-check-size.html</guid><pubDate>Mon, 09 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;In recent years I’ve seen several startups go for a
microservices-first approach. This is my two cents, distilled from
watching those projects unfold.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you’re Netflix or Amazon, one of your big problems will be
coordinating different teams and projects. Sooner or later, you’ll
hit a situation where you need to coordinate the release dates of five
different projects to get something major launched.&lt;/p&gt;
&lt;p&gt;On that day, you’re hosed.&lt;/p&gt;
&lt;p&gt;One sub-project will always slip, so five teams sit near-idle for a
month, burning time and money. Fast forward a year or two and you wake
up to six-month drop-dead release cycle with a month-five code-freeze
and a month-four crunch window. It’s horrible. And it never improves,
because coordinating groups of people is &lt;em&gt;hard&lt;/em&gt;. [Citation: Theresa
May, 2016-2018]&lt;/p&gt;
&lt;p&gt;If you’re in that situation, microservices are brilliant. They allow
you to turn a human-coordination problem into a system-coordination
problem. System coordination is still hard - supporting multiple
versions, dealing with concurrency issues, building distributed,
fault-tolerant systems - these are all properly, Computer Science
hard. But they’re tractable. Computer concurrency problems are a
pain, but you can solve them. People concurrency problems are the
nightmare scenario second only to herd-of-cats concurrency problems.&lt;/p&gt;
&lt;p&gt;Microservices turn people coordination problems into software
coordination problems. Microservices are the way out of a quagmire.&lt;/p&gt;
&lt;p&gt;But what if you don’t have those problems? What if you only have
twenty-odd developers, and you can coordinate just by talking to them?
What if your project coordination problems boil down to, “asking Andy
and Catherine if they’re ready?” Then by choosing microservices
you’ve created API versioning problems, created concurrency problems
and created distributed, fault-tolerant problems, all for no benefit.&lt;/p&gt;
&lt;p&gt;In the absence of the relevant people problems, microservices &lt;em&gt;create&lt;/em&gt;
software problems. Microservices are the way into a quagmire.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;&lt;strong&gt;Update (1/4/22)&lt;/strong&gt;
Lately I’ve been exposed to a different style of
building microservices which I’m still thinking through. The first
approach - the one I spoke about in this post - looks a lot like a
zoomed-out version of Object Orientation, in which you build systems
that are independent, stateful islands talking to each other through messages.&lt;/p&gt;
&lt;p&gt;The second approach to microservices looks a lot like a zoomed-out
version of Functional Programming, which you build systems that look
like streams of immutable data, with independent transformations on
those streams. I’m still thinking through the implications, and it
deserves a its own new blog post, but for now I’ve put some of my
thinking into this talk: &lt;a href=&quot;https://youtu.be/6LsvrlqLI1g&quot;&gt;Side Effects Are The Complexity
Iceberg&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Emacs Feature Branch Tip</title><link>https://blog.jenkster.com/2017/07/emacs-feature-branch-tip.html</link><guid isPermaLink="true">https://blog.jenkster.com/2017/07/emacs-feature-branch-tip.html</guid><pubDate>Sat, 29 Jul 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Like many of us, I like to work on feature branches. Branch,
commit-commit-commit, push, pull-request. It’s clean and easy.&lt;/p&gt;
&lt;p&gt;But sometimes I forget a step and screw my workflow up. I get to the
end of a round of commits and realise I forgot to &lt;code&gt;git branch&lt;/code&gt; before
I started coding. Now all my work is on local &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That’s fixable, but it’s a pain. You’ve probably been there, and there
are two solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new branch, stash, reset &lt;code&gt;master&lt;/code&gt; to &lt;code&gt;origin/master&lt;/code&gt;,
checkout the new branch and pop the stash.&lt;/li&gt;
&lt;li&gt;Or &lt;code&gt;git push origin master:feature&lt;/code&gt;, and hope that &lt;code&gt;origin/master&lt;/code&gt;
doesn’t move forward before the feature gets merged.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The former’s a pain and the latter relies on luck. Neither is ideal.&lt;/p&gt;
&lt;p&gt;Step forward Magit, the premium Emacs git
client. &lt;code&gt;magit-branch-spinoff&lt;/code&gt; automatically puts you back where you
want to be. It checks out a new branch based on your current &lt;code&gt;HEAD&lt;/code&gt;, and
resets &lt;code&gt;master&lt;/code&gt; back to &lt;code&gt;origin/master&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-docs&quot; id=&quot;user-content-fnref-docs&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. So, so easy.&lt;/p&gt;
&lt;p&gt;Unsurprisingly, it’s available from a &lt;code&gt;M-x&lt;/code&gt; near you, or from Magit’s
branch menu.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-docs&quot;&gt;
&lt;p&gt;You won’t ben surprised to learn it’s a bit more flexible than that, if you need it to be. See the docs. &lt;a href=&quot;#user-content-fnref-docs&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>There&apos;s Immutable And Then There&apos;s Immutable</title><link>https://blog.jenkster.com/2017/01/theres-immutable-and-then-theres-immutable.html</link><guid isPermaLink="true">https://blog.jenkster.com/2017/01/theres-immutable-and-then-theres-immutable.html</guid><pubDate>Wed, 25 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Following a brainwave, a scientist writes something important on a blackboard. Then in large, friendly letters he writes above it, “PLEASE DO NOT ERASE THIS!”&lt;br&gt;
He leaves the room to grab a coffee.&lt;br&gt;
Five minutes later he returns, and another scientist is cheerfully
cleaning the blackboard, removing all trace of that world-changing
idea.&lt;br&gt;
“B-b-but - didn’t you see the note???” yelps the first.&lt;br&gt;
“The one that said, ‘don’t rub this out?’” replies the second.&lt;br&gt;
“Yes!”&lt;br&gt;
“Oh…I thought it meant don’t get rid of the blackboard. I didn’t
realise the contents were important too.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So it may be with immutability. Take Scala for instance. Put an object
into a &lt;code&gt;scala.collection.immutable.List&lt;/code&gt; and the list is guaranteed
never to change. It will always be a one-element list with that object
in it. But the object itself? No special guarantees there - it’s
still mutable as it was before.&lt;/p&gt;
&lt;p&gt;In this case, the list is the wall and the object is the blackboard -
one is firmly nailed to the other. But just like the blackboard, the
object can change its meaning at will.&lt;/p&gt;
&lt;p&gt;Similarly, in recent JavaScript specs we have &lt;code&gt;Object.freeze()&lt;/code&gt; which
many will say makes a JavaScript object immutable. And technically it
does - the object’s keys will not change, and the pointers&lt;sup&gt;&lt;a href=&quot;#user-content-fn-pointers&quot; id=&quot;user-content-fnref-pointers&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
associated with those keys will not change, but the things they point
to might. JavaScript’s &lt;code&gt;Object.freeze()&lt;/code&gt; only freezes top-level
properties. In which case it might be better named
&lt;code&gt;Object.frosting()&lt;/code&gt;. Again, the blackboard is fixed, but what’s
written on it is a movable feast.&lt;/p&gt;
&lt;p&gt;All this seems odd coming from languages that have immutability as a
core concept, like Clojure &amp;amp; Haskell. In those languages, if I give
you access to my immutable list, you can do anything you like with it
and it won’t affect me. I don’t need to know what you did; I don’t
need to trust you to behave yourself; I can rely on guarantees from
the language itself.
If you try to write on my blackboard, you’ll find yourself transported
to another room, with an identical blackboard that you’re free to do
whatever you like with. Mine remains untouched.&lt;/p&gt;
&lt;p&gt;And so sadly it seems that, like “isomorphic”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-isomorphic&quot; id=&quot;user-content-fnref-isomorphic&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;,
“immutable” now has two meanings depending on where you first heard
about it. In the new meaning, you need to know some implementation
details before you can say what part of the data is fixed, and what is
subject to change. That doesn’t sound very immutable to me…&lt;/p&gt;
&lt;p&gt;(I confess I struggle to see the value of immutable frosting. It seems
like, “immutability made easy for the language implementor,” not,
“made valuable for the programmer.”)&lt;/p&gt;
&lt;p&gt;Still, for the record, here’s a definition of immutability that I
think’s unambiguous and useful:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you call a pure function with the same immutable argument, you always get the same result.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-river&quot; id=&quot;user-content-fnref-river&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds obvious, but up until a few days ago I thought that was the
only meaningful meaning ‘immutable’ could have…&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-pointers&quot;&gt;
&lt;p&gt;I’m still bothered by JavaScript being a language where there are no C-style pointers, but pointer-based semantics are &lt;em&gt;everywhere&lt;/em&gt;. &lt;a href=&quot;#user-content-fnref-pointers&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-isomorphic&quot;&gt;
&lt;p&gt;Meaning, “you can convert a value from one type to another and back without losing information,” or, “the same HTML can be rendered on the backend or the frontend.” &lt;a href=&quot;#user-content-fnref-isomorphic&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-river&quot;&gt;
&lt;p&gt;You really can cross the same river twice. &lt;a href=&quot;#user-content-fnref-river&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Type Bombs in Elm</title><link>https://blog.jenkster.com/2016/11/type-bombs-in-elm.html</link><guid isPermaLink="true">https://blog.jenkster.com/2016/11/type-bombs-in-elm.html</guid><pubDate>Tue, 08 Nov 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you want to make anyone on the core Elm team roll their eyes, just
pick a feature that Haskell has and say, “Elm should have it too.”
‘Typeclasses’ is the most common way to play the game, but you’ll get
extra hipster points if you say ‘Higher-Kinded Types’.&lt;/p&gt;
&lt;p&gt;So, I apologise in advance for this post, because it’s a bit, “Haskell
has X, Elm should have X too.” And I’ll try to justify why. But really
this post is about how Elm already has this &lt;code&gt;$BLESSED_FEATURE&lt;/code&gt;, if you
squint your eyes…&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Get to the point Kris - what’s the feature?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Type holes. They’re brilliant. I use them. I should use them
more. At &lt;a href=&quot;http://www.codemesh.io/&quot;&gt;CodeMesh&lt;/a&gt; last week I saw
University Professors popping them like Pez. But crucially for Elm,
they are huge-mongously useful for beginners. They make typed
functional programming easier at every level because they’re all about
getting fast, precise help when you don’t know what to do next.&lt;/p&gt;
&lt;p&gt;Let’s have a quick look at what they are, for the uninitiated, and
then I’ll outline a filthy little trick that gives you type holes in
Elm today.&lt;/p&gt;
&lt;h2 id=&quot;the-hole-truth&quot;&gt;The Hole Truth&lt;/h2&gt;
&lt;p&gt;If you’ve done any programming in Elm (or Haskell, or PureScript, or
…) you’ll know that the compiler always has an opinion on what the
type of a function should be. If you write this function in Elm:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;tally&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;    List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;foldl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;x ( trues, falses ) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            if &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                ( trues &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, falses )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                ( trues, falses &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        ( &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        xs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…the compiler knows what this function’s type is, even if you
don’t. And with the &lt;code&gt;--warn&lt;/code&gt; flag, it will happily tell you:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;markdown&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;Top-level value &lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;`tally`&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; does not have a type annotation.&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:#F8F8F2&quot;&gt;67| tally xs =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;^^^^^&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;I inferred the type annotation so you can copy it into your code:&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:#F8F8F2&quot;&gt;tally : List Bool -&amp;gt; ( number, number&apos; )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Maybe you could have figured that type out yourself. But why bother?
The compiler knows about types, and is supposed to be your
assistant. It’s happy to help.&lt;/p&gt;
&lt;p&gt;Type holes use the same mechanism at a more granular level. If the
compiler can assist you in figuring out the type of a function, why
can’t it help you figure out the type of an argument? Why can’t we
say:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;tally&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;    List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;foldl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;x ( trues, falses ) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            if &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                ( trues &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, falses )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                ( trues, falses &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;        HEY_COMPILER_WHAT_GOES_HERE_MY_FRIEND&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        xs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…and the compiler would say:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;markdown&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;Thank you for asking. I looked at the way the rest of the function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;uses that argument, and I think it should have the type:&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:#50FA7B&quot;&gt;        `( number, number&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:#F8F8F2&quot;&gt;Or somesuch thing. Tally-ho.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you’d say, “Oh yeah, a pair of numbers - that makes sense.” And
your ho would be well and truly tallied.&lt;/p&gt;
&lt;p&gt;Any time you get stuck on what type of argument you need, you can
stick in a marker to the compiler - a type hole - and it gives you its
best guess. It tells you what you’re looking for.&lt;/p&gt;
&lt;p&gt;(Actually, as far as I’ve seen, the experts don’t even wait to get
stuck. They have more holes than Trump’s tax return.)&lt;/p&gt;
&lt;p&gt;Type holes are simple, useful and universal. They save time &amp;amp;
head-scratching. They help.&lt;/p&gt;
&lt;h2 id=&quot;one-more-example&quot;&gt;One More Example&lt;/h2&gt;
&lt;p&gt;Before we get to the Elm-today part, there’s one other place we can
use holes: in the type signature. We’ve already seen that Elm can tell
you the type of the &lt;code&gt;tally&lt;/code&gt; function. But what if we were certain
about &lt;em&gt;part&lt;/em&gt; of the signature? What if we were sure we wanted it to
return a pair of numbers, but weren’t sure what the input type should
be? Type holes to the rescue:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;tally&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; HEY_COMPILER_WHAT_SAY_YOU_MY_FINE_FELLOW&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ( number, number&apos; )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;markdown&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;Thank you for asking. Of course, I could fill in the whole type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;signature, but I appreciate you doing some of the work. The missing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;piece looks like a:&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:#50FA7B&quot;&gt;    `List Bool`&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:#F8F8F2&quot;&gt;...to me. Making the whole signature:&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:#F8F8F2&quot;&gt;tally : List Bool -&amp;gt; ( number, number&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:#F8F8F2&quot;&gt;Now, why don&apos;t you stick that in and make a cup of tea with the time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;saved, what?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having type holes available in the signature makes sense - it means
that whether you’re stuck on the implementation or the design, you can
get some advice.&lt;/p&gt;
&lt;h2 id=&quot;half-a-hole-is-as-good-as-a-whole-one&quot;&gt;Half A Hole Is As Good As A Whole One&lt;/h2&gt;
&lt;p&gt;So that’s type holes. And Elm doesn’t have them. (Yet.) But the point
of this post is not to argue for their inclusion&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. No the point
of this post is, I use type holes in Elm already and I want to tell
you how. It’s a dirty, dirty trick, but it works and only God can
judge me.&lt;/p&gt;
&lt;p&gt;Here’s the secret: To get type holes in Elm, pick a primitive type
&lt;em&gt;that you know is wrong&lt;/em&gt;, and stick that in instead:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;tally&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;    List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;foldl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;x ( trues, falses ) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            if &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                ( trues &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, falses )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                ( trues, falses &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;LOLWAT&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        xs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Elm will react with suitable horror:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;markdown&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;74| )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;75|&amp;gt; &quot;LOLWAT&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;76| xs&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:#F8F8F2&quot;&gt;Function &lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;`foldl`&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; is expecting the 2nd argument to be:&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:#F8F8F2&quot;&gt;    ( number, number&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:#F8F8F2&quot;&gt;But it is:&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:#F8F8F2&quot;&gt;    String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There - I stuck in a &lt;code&gt;String&lt;/code&gt; knowing it was wrong. Elm borks and
tells me the discrepancy. It says, there’s a conflict between
&lt;code&gt;( number, number&apos; )&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt;. Since I know that &lt;code&gt;String&lt;/code&gt; is wrong,
I now know that &lt;code&gt;( number, number&apos; )&lt;/code&gt; is right. I have fooled Elm into
giving up the goods.&lt;/p&gt;
&lt;p&gt;Let’s quickly do the same at the type level. I’m unsure of the type of
the first argument, but I’m certain it’s not &lt;code&gt;Date&lt;/code&gt;, so we’ll use that:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;tally&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ( number, number&apos; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;tally&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Elm complains, but in doing so we’ve tricked it into giving us the
right answer:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;markdown&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;-- TYPE MISMATCH ---------------------------------------- ./src/Contact/Rest.elm&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:#F8F8F2&quot;&gt;The type annotation for &lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;`tally`&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; does not match its definition.&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:#F8F8F2&quot;&gt;67| tally : Date -&amp;gt; ( number, number&apos; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;The type annotation is saying:&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:#F8F8F2&quot;&gt;    Date -&amp;gt; ( number, number&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:#F8F8F2&quot;&gt;But I am inferring that the definition has this type:&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:#F8F8F2&quot;&gt;    List Bool -&amp;gt; ( number, number&apos; )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again there’s a disagreement - &lt;code&gt;Date&lt;/code&gt; isn’t right so &lt;code&gt;List Bool&lt;/code&gt; must be.&lt;/p&gt;
&lt;p&gt;So that’s it. Stick in a known-wrong answer and it will complain with
the right one.&lt;/p&gt;
&lt;p&gt;In the absence of a proper name I’m calling this trick a Type Bomb,
because if you don’t have a hole, a controlled explosion will do. Go
out there and make some shapes…&lt;/p&gt;
&lt;p&gt;Actually I can’t finish this note without recounting a conversation I had with
&lt;a href=&quot;https://twitter.com/jessitron&quot;&gt;@jessitron&lt;/a&gt; last week:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Me: You know what feature Elm should have?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Jessica: Type holes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Me: Type hol-. Wait, what did you say?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Jessica: Type holes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Me: Um, yeah. That.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So she totally stole my thunder, but at least great minds think alike.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;I’m quite certain Evan knows what a type hole is, just as he knows what typeclasses and higher-kinded types are, and he’s either going to put them in or he’s not. I shan’t be telling him what to do. (That said, if Evan happens to be reading, I will say that type holes help beginners as much as experts. More perhaps.) &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Functional Mumbo Jumbo - ADTs</title><link>https://blog.jenkster.com/2016/06/functional-mumbo-jumbo-adts.html</link><guid isPermaLink="true">https://blog.jenkster.com/2016/06/functional-mumbo-jumbo-adts.html</guid><pubDate>Fri, 10 Jun 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;What are “ADTs”?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Algebraic Data Types.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lovely. What the heck does that mean?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It means you can mix product and sum types together.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Okay. I have one more question, and please start answering in English: What are product and sum types?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Product types you’ll be deeply familiar with - it’s when you make a
new type by combining others. For example, you could define a &lt;code&gt;Person&lt;/code&gt;
type as the combination of a &lt;code&gt;String&lt;/code&gt; for their name, and an &lt;code&gt;Int&lt;/code&gt; for their
age. Like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Person&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…or like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        { name &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        , age &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Int&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In C that’d be a struct. In Java you’d probably call it a POJO. In
Clojure they say, “Just use a map.”&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Why’s it called a ‘product’ type?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It might help to think of how many possible values there are for
&lt;code&gt;Person&lt;/code&gt; now.&lt;/p&gt;
&lt;p&gt;It’s all the possible values for &lt;code&gt;String&lt;/code&gt;, multiplied by all the
possible values for &lt;code&gt;Int&lt;/code&gt;. It’s the multiple, or product, of the two
types.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Okay, product types combine types together. What’s a sum type?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, product types are a bit like an &lt;code&gt;AND&lt;/code&gt; operation, aren’t they?
They &lt;code&gt;AND&lt;/code&gt; types together. If you think of it that way, you’re
instantly going to start to wonder what an &lt;code&gt;OR&lt;/code&gt; would look like. For
that, we can pull out another old chestnut from the Big Book of Type
Examples. Chapter two, playing cards:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type Suit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Heart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Spade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Club&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Diamond&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A suit is a heart, or a spade, or a club, or a diamond. Any one of
those four values, but only one. It’s an exclusive-or, as a type.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So a sum type is just an enum?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well…yeah I suppose it is. But that’s not what makes this
interesting. An ADT isn’t just structs and enums, it’s the &lt;em&gt;free mixing
of them&lt;/em&gt; to make sophisticated data models.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Give me a concrete example.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Glad you asked. I’m going to make a credit card payment. When the
answer comes back from my payment provider, there are lots of things
that could happen. Hopefully it goes well and I get a receipt ID back
as a string. But maybe the card on file has expired, and I get a few
details about the card to prompt the user with. Or it just blows up with
different kinds of error. I can model all possible responses neatly
with an ADT, like so:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type PaymentResponse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Paid&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; CardExpired&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Date&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; HttpError&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; AuthError&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we have &lt;code&gt;Paid&lt;/code&gt;, which is a wrapper around a &lt;code&gt;String&lt;/code&gt;;
&lt;code&gt;CardExpired&lt;/code&gt; and &lt;code&gt;HttpError&lt;/code&gt; which are product types; and &lt;code&gt;AuthError&lt;/code&gt;
which is a “traditional” enum value. All mixed together in a sum type
to model all possible payment responses.&lt;/p&gt;
&lt;p&gt;Most languages don’t have support for this. They might have enums, but
not ones that carry data. You can’t have an enum of structs
or an enum of POJOs&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Clojure’s an interesting case where it does have ADTs, but they’re
possibly too flexible. You can mix together maps, lists and primitives
to make any shape of data you like. But you can suffer with the
exclusion problem. While you can say all these things are valid
responses:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:paid&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;eefa9112&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:card-expired&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;8783&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; #date &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;03/19&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:http-error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Server just exploded&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;:auth-error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…you have a harder time saying what &lt;em&gt;isn’t&lt;/em&gt; a valid response, like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:card-expired&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;we don&apos;t know why&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s where Plumatic schema and spec become essential.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So is that it? Is that all an ADT is?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No. You’re at the entrance to a delightful rabbit hole. ADTs can have
type variables, and can be further generalised, and all sorts of
useful stuff. But if you have the core idea - mixing and matching ANDs
and ORs to build up data models - you’re on your way.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So why is it useful?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Because data-modelling is the most important thing we do, so tools for
modelling data are fundamentally interesting. But let me give you a
concrete example of something cool to go away with. Once we’ve defined
our rich data type, a suitably-savvy compiler will be able to help us
use it properly. Here’s some pseudo-code to handle payment responses:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;handle&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; paymentResponse &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;paymentResponse &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;        Paid&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            insert db &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;receipts&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; db 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:#BD93F9&quot;&gt;        CardExpired&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; fourDigits date &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            notifyUser (&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Your card &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ++&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; fourDigits &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; expired on &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ++&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; date &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#BD93F9&quot;&gt;        HttpError&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; code msg &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            logError code msg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Did you spot the error in that code? You probably did, but the
compiler is guaranteed to notice:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; MISSING&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; PATTERNS&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ----------------------------------------------&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; src/Main.elm&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:#50FA7B&quot;&gt;This&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; `case`&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; have&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; branches&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; all&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; possibilities.&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:#8BE9FD&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:#50FA7B&quot;&gt;You&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; need&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; account&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; following&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; values:&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:#50FA7B&quot;&gt;    PaymentResponse.AuthError&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:#50FA7B&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; branch&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; cover&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; pattern!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The compiler knows which values &lt;code&gt;PaymentResponse&lt;/code&gt; can have, and so can check our case
statements for completeness. In this case, it’s instantly noticed that
we’ve ignored the authorization failure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sweet. Okay, last question. If there’s AND and OR…where’s NOT?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You mean a type that can be any type &lt;em&gt;except&lt;/em&gt; something?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Yeah.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Interesting question. Yup, that’d still be part of an Algebra of Data
Types, so it’d count. I’ve never seen it though. Let me know if you do…&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;And nearly every language has a way to get around it. In Java you’d use reflection on subclasses, perhaps. But first-class support? No. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>How Elm Slays a UI Antipattern</title><link>https://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html</link><guid isPermaLink="true">https://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html</guid><pubDate>Fri, 03 Jun 2016 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;There’s a bug in several places in the OSX Twitter client, and in at
least one place in the Slack client, and in &lt;em&gt;loads&lt;/em&gt; of other
apps. Here’s Twitter:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/twitter_zero.png&quot; alt=&quot;Twitter says no&quot;&gt;&lt;/p&gt;
&lt;p&gt;That’s not the correct data. When I go to this tweet, it shows “0
Retweets 0 Likes” for a few moments, until the real data loads in.&lt;/p&gt;
&lt;p&gt;Now here’s Slack:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/slack_zero.png&quot; alt=&quot;Slack says no&quot;&gt;&lt;/p&gt;
&lt;p&gt;Again, it’s not correct. when I go to the view it says, “no messages,”
as a placeholder until the actual data loads in. A few moments later
I get a big long list.&lt;/p&gt;
&lt;p&gt;It’s one of those UX patterns that crops up everywhere once you start
noticing it: showing zero or empty when you should be showing a
loading message. It’s incredibly common.&lt;/p&gt;
&lt;p&gt;Now I don’t have access to their source code, of course, but I’m
willing to bet that in most cases, it boils down to this broken data
model:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;javascript&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; data &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  loading&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  things&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Store a loading flag and an empty list/count of things you’re loading.
Then in the UI, you’re supposed to check the loading flag before you
display the things.&lt;/p&gt;
&lt;p&gt;Inevitably someone forgets, and so on a slow connection the UI
immediately displays the, “No Things Found,” message until the
response comes back.&lt;/p&gt;
&lt;p&gt;We’ve all done it. Especially when deadlines are tight and people
start planning whole sprints around, “the happy path.” But it’s poor
UX, and it’s a shame to spoil a quality experience on such a small
detail.&lt;/p&gt;
&lt;p&gt;Now, how can we fix this? Discipline? Linters? More unit tests? A QA
army? No! Let’s fix the data model, because fixing the data model is
fastest, cheapest, most reliable fix there is.&lt;/p&gt;
&lt;h2 id=&quot;to-elm&quot;&gt;To Elm!&lt;/h2&gt;
&lt;p&gt;Let’s move over to Elm, because we’ll need a language with explicit
data models if we’re going to talk about this properly. So here’s an
absolutely basic version of this data model, and it’s a wrong ’un:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type alias Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    { things &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Thing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you think about it, this broken from the outset. It’s saying that you
will always have a list of things available, which isn’t true when we
startup. And that causes the display bug.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;A much better model would be:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type alias Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    { things &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Maybe&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Thing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can represent, “we haven’t loaded things yet,” naturally. On
startup the list of things is &lt;code&gt;Nothing&lt;/code&gt;. When the load completes it
becomes &lt;code&gt;Just [thing1, thing2, ...]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If the server replies that there genuinely were no things, then that’s
&lt;code&gt;Just []&lt;/code&gt;. Now the empty list actually means the empty list, it’s no
longer doing double-duty as the “not loaded” case.&lt;/p&gt;
&lt;p&gt;You can do this in JavaScript of course, but you won’t. Long
experience will have taught you that setting a property to &lt;code&gt;null&lt;/code&gt; may
be correct, but it’s just asking for runtime exceptions. Hence the
separate loading flag, which gets forgotten.&lt;/p&gt;
&lt;p&gt;In Elm, you can not only handle the nothing case safely, but the
compiler will actively nag you to remember to write the “Loading”
message:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&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:#50FA7B&quot;&gt;someView&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;things &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    Just&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; things &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…and when we compile:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; MISSING&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; PATTERNS&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ----------------------------------------------&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; src/View.elm&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:#50FA7B&quot;&gt;This&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; `case`&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; have&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; branches&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; all&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; possibilities.&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:#8BE9FD&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:#50FA7B&quot;&gt;You&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; need&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; account&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; following&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; values:&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:#50FA7B&quot;&gt;    Maybe.Nothing&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:#50FA7B&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; branch&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; cover&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; pattern!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We get an error message about missing out the loading case, &lt;em&gt;exactly&lt;/em&gt;
where the solution needs to go.&lt;/p&gt;
&lt;p&gt;On the surface it seems like we’ve made a simple data-model change,
but by reshaping the data it becomes &lt;em&gt;much&lt;/em&gt; easier to ensure an
improved user experience. Win.&lt;/p&gt;
&lt;h2 id=&quot;the-leveling-up&quot;&gt;The Leveling-Up&lt;/h2&gt;
&lt;p&gt;I like this, but I reckon we can be much more sophisticated. And Elm
will still make it easy when we do. In my mental model, REST requests
have one of four states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We haven’t asked yet.&lt;/li&gt;
&lt;li&gt;We’ve asked, but we haven’t got a response yet.&lt;/li&gt;
&lt;li&gt;We got a response, but it was an error.&lt;/li&gt;
&lt;li&gt;We got a response, and it was the data we wanted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In a language with nice data-modelling facilities, we can easily create
something that represents these four states:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type RemoteData&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; e a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; NotAsked&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Loading&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Failure&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; e&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Success&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is like a &lt;code&gt;Result&lt;/code&gt; or &lt;code&gt;Either&lt;/code&gt; type, where we can have parameters
for the &lt;code&gt;Failure&lt;/code&gt; and &lt;code&gt;Success&lt;/code&gt; types, plus tracking for the
&lt;code&gt;NotAsked&lt;/code&gt; and &lt;code&gt;Loading&lt;/code&gt; states.&lt;/p&gt;
&lt;p&gt;Now in our data model, we can properly represent the list of things as
something we fetch from an external source:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  type alias &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      { things &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; RemoteData&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Http&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Thing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s make a quick refinement to that - most of our external requests
are REST requests, so the error type is nearly always an
&lt;code&gt;Http.Error&lt;/code&gt;. A quick alias tidies that up:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  type alias &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;WebData&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;      RemoteData&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Http&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; a&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&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  type alias &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      { things &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; WebData&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Thing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The nice thing about this data model in Elm is, the compiler will now
force you to write the correct UI code. It will keep track of the
possibility of “things not loaded” and errors, and &lt;em&gt;force&lt;/em&gt; you to
handle them all in the UI.&lt;/p&gt;
&lt;p&gt;Personally, I love it. A bit of thought about the data model, a couple
of utterly-reusable definitions, and for the rest of the project the
compiler will be at our backs, pushing us towards better UX. Happier
users at bargain prices.&lt;/p&gt;
&lt;h2 id=&quot;the-download&quot;&gt;The Download&lt;/h2&gt;
&lt;p&gt;If you want to play with this, I’ve published it as a standalone
package which you can add to your project with:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; elm&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; krisajenkins/remotedata&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://package.elm-lang.org/packages/krisajenkins/remotedata/latest&quot;&gt;Here are the docs&lt;/a&gt;, and happy modelling!&lt;/p&gt;
</content:encoded></item><item><title>Clojure-Fu with Juxt</title><link>https://blog.jenkster.com/2016/06/clojure-fu-with-juxt.html</link><guid isPermaLink="true">https://blog.jenkster.com/2016/06/clojure-fu-with-juxt.html</guid><pubDate>Wed, 01 Jun 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I love &lt;code&gt;juxt&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. But I was reminded yesterday that not everyone
has made friends with it. So, to give it a little of the limelight it
deserves, I thought I’d write down My Favourite Juxt Trick.&lt;/p&gt;
&lt;h2 id=&quot;the-recap&quot;&gt;The Recap&lt;/h2&gt;
&lt;p&gt;First, let’s recap what &lt;code&gt;juxt&lt;/code&gt; does: it lets you pass the same
arguments to several functions in a row. So if you want to find out a
person’s name &amp;amp; height, you can do this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; name-and-height&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;juxt&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :name&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :height&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;name-and-height&lt;/code&gt; is now a single function that returns both results
as in a vector:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; person {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Kris&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;             :height&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 172&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;             :devastating-handsomeness-factor&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;println&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;name-and-height&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; person))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;;=&amp;gt; [Kris 172]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nothing special there. It’s just calling each function, &lt;code&gt;:name&lt;/code&gt; and
&lt;code&gt;:height&lt;/code&gt;, with the same arguments, and gathering up the results.&lt;/p&gt;
&lt;h2 id=&quot;the-trick&quot;&gt;The Trick&lt;/h2&gt;
&lt;p&gt;Now let’s do something cool with it. I’ve got a list of people working
in different departments:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; people [{&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Brad&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;     :salary&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 27000&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :department&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;hats&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Janet&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    :salary&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 54000&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :department&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;capes&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Eddie&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    :salary&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 19500&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :department&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;hats&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Frank&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    :salary&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 98000&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :department&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;capes&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Rocky&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    :salary&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 18000&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :department&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;shoes&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’d like to roll those up by department and largesse. First let’s
define what counts as highly-paid, using a number that’s entirely
fictional in London:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; highly-paid? [x]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 30000&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:salary&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have two functions, and we can group by both of them:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;pprint&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;group-by&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;juxt&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :department&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; highly-paid?)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;           people))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{[&quot;hats&quot; false]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [{:name &quot;Brad&quot;, :salary 27000, :department &quot;hats&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {:name &quot;Eddie&quot;, :salary 19500, :department &quot;hats&quot;}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [&quot;capes&quot; true]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [{:name &quot;Janet&quot;, :salary 54000, :department &quot;capes&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {:name &quot;Frank&quot;, :salary 98000, :department &quot;capes&quot;}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [&quot;shoes&quot; false] [{:name &quot;Rocky&quot;, :salary 18000, :department &quot;shoes&quot;}]}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There - we’ve just built an on-the-fly, composite-key index of our
data, for free.&lt;/p&gt;
&lt;p&gt;Any time you need to filter some data by multiple criteria, &lt;code&gt;juxt&lt;/code&gt;
comes in mighty handy.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Sorry &lt;a href=&quot;https://juxt.pro/&quot;&gt;Juxt&lt;/a&gt;. I love you too, but this one is about your namesake. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>How I Structure Elm Apps</title><link>https://blog.jenkster.com/2016/04/how-i-structure-elm-apps.html</link><guid isPermaLink="true">https://blog.jenkster.com/2016/04/how-i-structure-elm-apps.html</guid><pubDate>Sat, 16 Apr 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Updated: 1st Aug 2016 for Elm 0.17.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With the rise of people getting to grips with Elm, I’m hear several
folks wondering how to make the transition from play project to a
larger app. So, in the hope that it helps ease that transition, here’s
my guide to structuring large Elm apps. Follow along and you should
have an easier time.&lt;/p&gt;
&lt;h2 id=&quot;startup&quot;&gt;Startup&lt;/h2&gt;
&lt;p&gt;First, there are two packages that begin every Elm app, so
let’s install them:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;elm&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; --yes&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; elm-lang/core&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;elm&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; --yes&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; elm-lang/html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then I’ll edit the &lt;code&gt;elm-package.json&lt;/code&gt; file that’s just been created
and set &lt;code&gt;source-directories&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;json&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;source-directories&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that in place, we can talk about file structure. There’s one
special file, and a then a pattern that repeats throughout the app.&lt;/p&gt;
&lt;h3 id=&quot;srcappelm&quot;&gt;&lt;code&gt;src/App.elm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The special file is the app’s entry point. I typically call it
&lt;code&gt;src/App.elm&lt;/code&gt;, though some choose &lt;code&gt;src/Main.elm&lt;/code&gt;. If you were building
several different Elm apps from the same code base, I might name the
entry points more specifically, like &lt;code&gt;src/Public.elm&lt;/code&gt; and
&lt;code&gt;src/Admin.elm&lt;/code&gt;. But for now, let’s just talk about a single entry point.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App&lt;/code&gt; contains as little as possible to get the app started, which is
usually just:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Html&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;App&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; State&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; View&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&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Program&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Never&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;    Html&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;App&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        { init &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; State&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;initialState&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        , update &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; State&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        , subscriptions &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; State&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;subscriptions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        , view &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;rootView&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code is pretty much lifted from the docs. The only
difference is this is /all/ just wiring. The real code has been moved
out into a repeating pattern of four files.&lt;/p&gt;
&lt;h2 id=&quot;the-featureful-four&quot;&gt;The Featureful Four&lt;/h2&gt;
&lt;p&gt;Every feature, subfeature, page, widget and gizmo will have its own
directory, and in that directory there will almost certainly be
these four files:&lt;/p&gt;
&lt;h3 id=&quot;featuretypeselm&quot;&gt;&lt;code&gt;.../feature/Types.elm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Types&lt;/code&gt; houses the type definitions for this feature. At a
minimum, it will contain &lt;code&gt;Model&lt;/code&gt; and &lt;code&gt;Msg&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type alias Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;type Msg&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…plus any other types that are unique to this feature.&lt;/p&gt;
&lt;p&gt;It will also house generic functions on those types. Not application
logic, but library functions to make working with those types easier.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Types&lt;/code&gt; will typically export everything, and use anything from
subfeatures’ &lt;code&gt;Types&lt;/code&gt;, so the top of the file will look like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;featurestateelm&quot;&gt;&lt;code&gt;.../feature/State.elm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This is the brain of each feature. Shaped by &lt;code&gt;Html.App&lt;/code&gt;, this will
contain a minimum of three declarations, The &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and
&lt;code&gt;subscriptions&lt;/code&gt; functions. First, &lt;code&gt;init&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ( &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Cmd&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is what must be set up to start using this feature. Any parent
that makes use of this feature agrees to pull this in when it starts
using it.&lt;/p&gt;
&lt;p&gt;It’s perfectly fine for &lt;code&gt;init&lt;/code&gt; to be a function instead of a
value. For example, you might have a reservation widget that expires
after 15 minutes, so needs to know its startup time:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Time&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ( &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Cmd&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; startTime &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the starting state in place, next we need the update function:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ( &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Cmd&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; action model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the function that reacts to events, triggers external effects
and steps the app forward in time. If you’re changing or debugging
application logic, you’ll start working here.&lt;/p&gt;
&lt;p&gt;Last we need subscriptions, which may be as simple as:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Sub&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or may actually do its own work:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Sub&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;  Websocket&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;listen &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;ws://echo.websocket.org&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Echo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or even mix in the subscriptions of children:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Sub&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;    Sub&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        [ &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Websocket&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;listen &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;ws://echo.websocket.org&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        , &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Child&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;subscriptions model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;child&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;            |&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Sub&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;map &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;ChildMsg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;State&lt;/code&gt; will usually just export these three key components, and
will expect them of its sub-components:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;subscriptions&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (..)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;State&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;State&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;featureviewelm&quot;&gt;&lt;code&gt;.../feature/View.elm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;View&lt;/code&gt; contains rendering code. Things with the type signature
&lt;code&gt;... -&amp;gt; Html Msg&lt;/code&gt;, and rarely anything else. I name the entry point
&lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Html&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Msg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;View&lt;/code&gt; will usually only export &lt;code&gt;root&lt;/code&gt;, and will use subfeatures’
&lt;code&gt;Types&lt;/code&gt; model &amp;amp; &lt;code&gt;View.root&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;View&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Html&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;App&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (..)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;View&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;View&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:#FF79C6&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;grommitList&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;    Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;View&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;root model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;grommits&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;        |&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Html&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;map &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;GrommitMsg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;featurerestelm&quot;&gt;&lt;code&gt;.../feature/Rest.elm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Last is RESTful code (HTTP and JSON-handling), which I name &lt;code&gt;Rest&lt;/code&gt;.
Not every feature needs such code, of course, but it’s so common that
it’s worth describing.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Rest&lt;/code&gt; namespace contains HTTP calls, and JSON encoders/decoders,
and little else.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Rest&lt;/code&gt; will usually export everything, and may use subfeatures’
&lt;code&gt;Types&lt;/code&gt; &amp;amp; &lt;code&gt;Rest&lt;/code&gt; modules:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Rest&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Feature&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (..)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Widget&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Rest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Grommit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Rest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;Along with the top-level &lt;code&gt;App.elm&lt;/code&gt;, that pattern-of-four describes the
vast majority of my directories in all of my Elm projects. As a layout
it works well. The pattern makes everything easier to find and modify,
as it answers a lot of useful questions without thinking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Q. Where’s the code for registration?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A. Look for a directory called &lt;code&gt;Registration&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q. Where’s the code for feature X?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A. Look for a directory called &lt;code&gt;X&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q. X doesn’t look right.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A. Look in &lt;code&gt;X/View.elm&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q. X doesn’t behave right.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A. Look in &lt;code&gt;X/State.elm&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q. X needs a new feature.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A. Start by changing the data-model in &lt;code&gt;X/Types.elm&lt;/code&gt;, and then follow the compiler messages through.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q. Our API is changing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A. Start by changing &lt;code&gt;X/Rest.elm&lt;/code&gt;, and then follow the compiler messages through.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There’s very little surprise and a good default organization. The
really nice thing about it is that it works recursively. You can use
this layout in every feature and sub-feature and sub-sub-features.&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; App.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Types.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; State.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; View.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; FrontPage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Rest.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; State.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Types.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; └──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; View.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Rest.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; State.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Types.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;│  &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; └──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; View.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Registration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;    ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Rest.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;    ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; State.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;    ├──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; Types.elm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;    └──&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; View.elm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;caveats&quot;&gt;Caveats&lt;/h2&gt;
&lt;p&gt;Take this pattern as a default, and remember to think for yourself. In
my codebases you’ll find features that are so tiny that I occasionally
stick the whole thing in one file. (Not often, but sometimes.) And
you’ll certainly files other than these four, for special
use-cases. But this simple approach covers a lot of ground, neatly.&lt;/p&gt;
</content:encoded></item><item><title>Git for Static Sites</title><link>https://blog.jenkster.com/2016/02/git-for-static-sites.html</link><guid isPermaLink="true">https://blog.jenkster.com/2016/02/git-for-static-sites.html</guid><pubDate>Tue, 09 Feb 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I often find myself creating static websites, where I want to push the
source to Github, and publish the result somewhere, quickly and
cheaply.&lt;/p&gt;
&lt;p&gt;One example is presentations, which I write in &lt;code&gt;org-mode&lt;/code&gt; and then
publish using &lt;code&gt;reveal.js&lt;/code&gt;. Another is Elm sites, when I build the site
in Elm and need to host the generated HTML/JavaScript, without
necessarily wanting a custom backend.&lt;/p&gt;
&lt;p&gt;So, here’s how I do it. Follow along and you’ll learn a practical
trick for publishing, and some &lt;em&gt;git-fu&lt;/em&gt; to boot…&lt;/p&gt;
&lt;h2 id=&quot;publish-on-github&quot;&gt;Publish on Github&lt;/h2&gt;
&lt;p&gt;The first thing to know is that those generous souls at Github will
publish your static sites for free. If you create any repo with a
branch called &lt;code&gt;gh-pages&lt;/code&gt;, they’ll publish it that branch on
&lt;code&gt;&amp;lt;your-username&amp;gt;.github.io/&amp;lt;repo-name&amp;gt;&lt;/code&gt; a few minutes later.&lt;/p&gt;
&lt;p&gt;So you could just create a brand new repository, commit your
compiled-down site to it, and rename &lt;code&gt;master&lt;/code&gt; to &lt;code&gt;gh-pages&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That would do the job, but we can improve things.&lt;/p&gt;
&lt;h2 id=&quot;orphan-branches&quot;&gt;Orphan Branches&lt;/h2&gt;
&lt;p&gt;Keeping two separate-but-related repos, one for the source and one for
the output, gets old quickly. Especially for small projects. Ideally
I’d like two separate project trees managed in the same &lt;code&gt;.git&lt;/code&gt;
directory, to keep everything together. And there’s something that
feels &lt;em&gt;correct&lt;/em&gt; about managing the two facets of the project in one
place. Doing exactly that is very easy:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; checkout&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; --orphan&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; gh-pages&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you checkout an ‘orphan’ branch, git creates an entirely new
branch without any parent commits (hence the name, ‘orphan’). You can
add anything you want to that branch, and it’s separate from the main
history, but stored in the same &lt;code&gt;.git&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;After creating an orphan branch you can clear out the current
directory - safe in the knowledge that it’s all still saved on
&lt;code&gt;master&lt;/code&gt; - and add any new content you want. The orphan branch has its
own timeline and own files, but it’s housed within the same git repo.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;git push -u origin gh-pages&lt;/code&gt; the first time you want
to push, and from then on &lt;code&gt;git push&lt;/code&gt; will send &lt;code&gt;master&lt;/code&gt;, publishing
your source, and &lt;code&gt;gh-pages&lt;/code&gt;, publishing your site.&lt;/p&gt;
&lt;p&gt;We just need one more piece to make this work really smoothly.&lt;/p&gt;
&lt;h2 id=&quot;worktrees&quot;&gt;Worktrees&lt;/h2&gt;
&lt;p&gt;The only problem with the orphan branch approach is that the workflow
typically goes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checkout &lt;code&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Build the site to &lt;code&gt;/dist&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Checkout &lt;code&gt;gh-pages&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Copy the contents of &lt;code&gt;/dist&lt;/code&gt; up to the top level.&lt;/li&gt;
&lt;li&gt;Commit and push.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s fine, but the file-copying is a little unwieldy. The solution, that makes
this whole approach flow smoothly, is using git worktrees - a new feature in
git 2.5.&lt;/p&gt;
&lt;p&gt;With worktrees, you can have two completely separate working
directories, backed by the same git repo. It’s a feature I use when I
want to flip between active-branches without stashing all the time.
(For example, when you’re blocked halfway through feature A, so you
want to crack on with feature B, but you know you’ll need to flip back
and forth.)&lt;/p&gt;
&lt;p&gt;For our purposes though, worktrees allow us to build directly to our
&lt;code&gt;gh-pages&lt;/code&gt; branch. We start a worktree off like so:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; pwd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;/.../my-project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; worktree&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ../my-project-dist&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; gh-pages&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have two directories side-by-side:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; /my-project&lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;       # Checked out as master&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; /my-project-dist&lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;  # Checked out as gh-pages&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we just alter our build script to build into &lt;code&gt;../my-project-dist&lt;/code&gt;
and the setup’s complete. Any commits in either directory get stored
on the same repo. And pushes, pulls or fetches will synchronise
exactly as you’d hope.&lt;/p&gt;
&lt;h2 id=&quot;to-recap&quot;&gt;To Recap&lt;/h2&gt;
&lt;h3 id=&quot;why&quot;&gt;Why?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You want to manage a source and a release repo.&lt;/li&gt;
&lt;li&gt;With easy publishing of the release repo.&lt;/li&gt;
&lt;li&gt;With the minimum of admin.&lt;/li&gt;
&lt;li&gt;With a guarantee that if you’ve got one, you’ve got the other.&lt;/li&gt;
&lt;li&gt;With a guarantee that if you’ve backed-up one, you’ve backed-up the other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how&quot;&gt;How&lt;/h3&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;# Create the orphan gh-pages branch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; checkout&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; --orphan&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; gh-pages&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:#6272A4&quot;&gt;# Create at least one commit.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD&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:#6272A4&quot;&gt;# Connect local gh-pages to the remote version.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; push&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; origin&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; gh-pages&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:#6272A4&quot;&gt;# Head back to master.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; checkout&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; master&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:#6272A4&quot;&gt;# Check out the orphan gh-pages branch in its own directory.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; worktree&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ../my-project-dist&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; gh-pages&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&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;# Finally, from now on, to publish both the source and the release it&apos;s just.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; push&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content:encoded></item><item><title>What Is Functional Programming?</title><link>https://blog.jenkster.com/2015/12/what-is-functional-programming.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/12/what-is-functional-programming.html</guid><pubDate>Tue, 29 Dec 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This is my take on what functional programming really is, in a way that will make sense to a jobbing programmer just trying to Get Stuff Done.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I put it to you that every function you write has two sets of inputs
and two sets of outputs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Two? Only one, surely?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No, two. Definitely two. Let’s take a look at the first pair with this
example:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; square&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&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:#6272A4&quot;&gt;// NOTE: The language doesn&apos;t matter, but I&apos;ve picked one with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;// explicit input &amp;amp; output types, for emphasis.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, the input you’re used to thinking about is &lt;code&gt;int x&lt;/code&gt;, and the
output you’re used to is also an &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That’s the first set of inputs &amp;amp; outputs. The traditional set, if you
will. Now let’s see an example of the &lt;em&gt;second&lt;/em&gt; set of inputs and
outputs:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;js&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;public &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; processNext&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    Message message &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; InboxQueue.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;popMessage&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (message &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;        process&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(message);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;According to the syntax, this function takes no inputs and returns no
output, and yet it’s obviously depending on something, and it’s
obviously doing something. The fact is, it has a &lt;em&gt;hidden&lt;/em&gt; set of
inputs and outputs. The hidden input is the state of the &lt;code&gt;InboxQueue&lt;/code&gt;
before the &lt;code&gt;popMessage()&lt;/code&gt; call, and the hidden outputs are whatever
&lt;code&gt;process&lt;/code&gt; causes, plus the state of &lt;code&gt;InboxQueue&lt;/code&gt; after we’re done.&lt;/p&gt;
&lt;p&gt;Make no mistake - the state of &lt;code&gt;InboxQueue&lt;/code&gt; is a genuine input of this
function. The behaviour of &lt;code&gt;processNext&lt;/code&gt; cannot be known without
knowing that value. And it’s a genuine output too - the result of
calling &lt;code&gt;processNext&lt;/code&gt; cannot be fully understood without considering
the new state of &lt;code&gt;InboxQueue&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So the second piece of code has hidden inputs and outputs. It requires
things, and causes things, but you could never guess what just by
looking at the API.&lt;/p&gt;
&lt;p&gt;These hidden inputs and outputs have an official name:
“side-effects”. There are many kinds of side-effects, but they all
come together under the same concept: “when we call this function,
what does it need that isn’t in the argument list, and what does it do
that isn’t part of the return value?”&lt;/p&gt;
&lt;p&gt;(Actually I think we need two terms: “side-effects” for the hidden
outputs, and “side-causes” for the hidden inputs. For most of the rest
of this post I’ll use “side-effects” for brevity, but I’m definitely
talking about side-causes too. I’m talking about all &lt;em&gt;hidden&lt;/em&gt; inputs
and outputs.)&lt;/p&gt;
&lt;h2 id=&quot;side-effects-are-the-complexity-iceberg&quot;&gt;Side-Effects are the Complexity Iceberg&lt;/h2&gt;
&lt;p&gt;When functions have side-effects (and side-causes), you can look at a
function like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; processMessage&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Channel&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; channel) {...}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…and think you’ve got an idea of what it’s doing, and be totally
wrong. There’s no way to know what it requires or what it will do
without looking inside. Does it take a message off the channel and
process it? Probably. Does it close your channel if some condition is
true? Maybe. Does it update a count in the database somewhere?
Perhaps. Does it explode if it can’t find the logging directory path
it was expecting? It might.&lt;/p&gt;
&lt;p&gt;Side-effects are the complexity iceberg. You look at the function
signature, and the name, and think you’ve got a sense of what you’re
looking at. But hidden beneath the surface of the function signature
could be absolutely anything. Any hidden requirement, any hidden
change. Without looking at the implementation, you’ve no way of
knowing what’s really involved. Beneath the surface of the API is a
potentially vast block of extra complexity. To grasp it, you’ll only
have three options: dive down into the function definition, bring the
complexity to the surface, or ignore it and hope for the best. And in
the end, ignoring it is usually a titanic mistake.&lt;/p&gt;
&lt;h2 id=&quot;isnt-this-what-encapsulations-about&quot;&gt;Isn’t This What Encapsulation’s About?&lt;/h2&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;p&gt;Encapsulation is about hiding implementation details. About hiding the
innards of the code so the caller doesn’t need to worry about
them. That remains a good principle, but it’s not what we’re talking
about.&lt;/p&gt;
&lt;p&gt;Side-effects aren’t about “hiding implementation details” - they’re
about hiding the code’s relationship with the outside world. A
function with side-causes has undocumented assumptions about what
&lt;em&gt;external&lt;/em&gt; factors it’s depending on. A function with side-effects has
undocumented assumptions about what &lt;em&gt;external&lt;/em&gt; factors it’s going to
change.&lt;/p&gt;
&lt;h2 id=&quot;are-side-effects-bad&quot;&gt;Are Side-Effects Bad?&lt;/h2&gt;
&lt;p&gt;When they work exactly as the original programmer expected, no,
they’re probably fine. But there’s the rub: we have to trust that the
the hidden expectations of the original programmer were correct, and
will remain correct as time marches on.&lt;/p&gt;
&lt;p&gt;Have we set up the state of the world the way this function expected
when it was written? Or did the world get changed somewhere? Perhaps
because a seemingly-unconnected piece of code changed. Or because
we’re installing the software in a new environment. Hidden assumptions
about the state of the world mean we have hidden hopes that it’s
similar enough to work.&lt;/p&gt;
&lt;p&gt;Can we test this code? Not in isolation. Unlike a circuit board, we
can’t just plug into its inputs and check its outputs. We have to
break open the code, figure out its &lt;em&gt;hidden&lt;/em&gt; causes and effects, and
simulate the world it’s supposed to exist in. I’ve seen several
TDD’ers spin in circles about whether they should do black box or
white box testing. The answer is, you ought to do black box testing -
you ought to be able to ignore the implementation details - but if you
allow side-effects, you can’t. Side-effects close the door to black
box testing, because you can’t get to the inputs &amp;amp; outputs without
cracking the box open and learning what’s inside.&lt;/p&gt;
&lt;p&gt;This effect is amplified for debugging. If a function doesn’t allow
side-effects (or side-causes), you can understand whether it’s correct
just by giving it some inputs and checking the outputs. But a function
with side-effects? There’s no upper-limit to how many other parts of
the system you’ll have to consider. When it’s allowed to depend on
anything, and cause anything, then the bugs could be anywhere.&lt;/p&gt;
&lt;h2 id=&quot;we-can-always-surface-side-effects&quot;&gt;We Can Always Surface Side-Effects&lt;/h2&gt;
&lt;p&gt;Can we do anything about this complexity? Yes. It’s actually pretty
simple to get started: If a function has something as an input, just
say so. If it returns something as an output, declare it. Simple as that.&lt;/p&gt;
&lt;p&gt;Let’s try an example. Here’s a function with a hidden input. Bonus
points if you spot it quickly:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Program&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; getCurrentProgram&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;TVGuide&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; guide, &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; channel) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;  Schedule&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; schedule &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; guide.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;getSchedule&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(channel);&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:#8BE9FD;font-style:italic&quot;&gt;  Program&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; current &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; schedule.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;programAt&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6;font-weight:bold&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#FF79C6&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; current;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function has a hidden input of the current time (&lt;code&gt;new Date()&lt;/code&gt;). We can surface this complexity by just being honest about
this extra input:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Program&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; getProgramAt&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;TVGuide&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; guide, &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; channel, &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; when) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;  Schedule&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; schedule &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; guide.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;getSchedule&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(channel);&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:#8BE9FD;font-style:italic&quot;&gt;  Program&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; program &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; schedule.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;programAt&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(when);&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:#FF79C6&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; program;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function now has no hidden inputs (or outputs).&lt;/p&gt;
&lt;p&gt;Let’s look at the pros and cons of this new version:&lt;/p&gt;
&lt;h3 id=&quot;cons&quot;&gt;Cons&lt;/h3&gt;
&lt;p&gt;It &lt;em&gt;looks&lt;/em&gt; more complex. It has three arguments instead of two.&lt;/p&gt;
&lt;h3 id=&quot;pros&quot;&gt;Pros&lt;/h3&gt;
&lt;p&gt;It isn’t more complex. Hiding a dependency didn’t make it simpler,
being honest about it doesn’t make it more complex.&lt;/p&gt;
&lt;p&gt;It’s vastly easier to test. Testing different times of day, clock
changes, leap years, will all be straightforward, because we can pass
in any time we like. I’ve seen code like the first version in
production, with all sorts of clever tricks to spoof the current
system clock for testing’s sake. Imagine the effort, when we can just
make it a parameter!&lt;/p&gt;
&lt;p&gt;It’s easier to reason about: This function now just describes a
relationship between its inputs and its outputs. If you know the
inputs, you know what the result should be, and you know everything
about the result. &lt;em&gt;This is a big deal&lt;/em&gt;. We can verify this code in
isolation. As long as we’ve tested the relationship between inputs and
outputs, we’ve tested the whole of the function.&lt;/p&gt;
&lt;p&gt;(And as an aside, it’s also more useful. We get, “what program starts in
an hour?” code for free.)&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-pure-function&quot;&gt;What is a ‘Pure Function’?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Drumroll please.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, finally, with an awareness of hidden inputs &amp;amp; outputs, we can
give, “a jobbing programmer’s definition of pure functions”:&lt;/p&gt;
&lt;p&gt;A function is called ‘pure’ if all its inputs are &lt;em&gt;declared&lt;/em&gt; as
inputs - none of them are hidden - and likewise all its outputs are
&lt;em&gt;declared&lt;/em&gt; as outputs.&lt;/p&gt;
&lt;p&gt;In contrast, if it has hidden inputs or outputs, it’s ‘impure’, and
the contract we think the function offers is only half the story. The
iceberg of complexity looms. We can never use impure code “in
isolation”. We can never test it in isolation. It always depends on
other things which we have to keep track of whenever we want to test
or debug.&lt;/p&gt;
&lt;h2 id=&quot;what-is-functional-programming&quot;&gt;What is ‘Functional Programming’?&lt;/h2&gt;
&lt;p&gt;With an awareness of pure and impure functions, we can now give,
“a jobbing programmer’s definition of functional programming”:&lt;/p&gt;
&lt;p&gt;Functional programming is about writing pure functions, about removing
hidden inputs and outputs as far as we can, so that as much of our
code as possible &lt;em&gt;just&lt;/em&gt; describes a relationship between inputs and
outputs.&lt;/p&gt;
&lt;p&gt;We accept that some side-effects are inevitable - most programs are
run for what they &lt;em&gt;do&lt;/em&gt; rather than what they return, but within our
program we will exercise tight control. We will eliminate side-effects
(and side-causes) wherever we can, and tightly control them whenever
we can’t.&lt;/p&gt;
&lt;p&gt;Or put another way: Let’s not hide what a piece of code needs, nor
what results it will yield. If a piece of code needs something to run
correctly, let it say so. If it does something useful, let it declare
it as an output. When we do this, our code will be clearer. Complexity
will come to the surface, where we can break it down and deal with it.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-functional-programming-language&quot;&gt;What is a ‘Functional Programming Language’?&lt;/h2&gt;
&lt;p&gt;Every language supports pure functions - it’s hard to make &lt;code&gt;add(x, y)&lt;/code&gt;
impure&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. And in many cases converting an impure function to a
pure one is just a case of lifting &lt;em&gt;all&lt;/em&gt; its inputs and outputs into
the function signature, so that the signature totally describes its
behaviour. So are all programming languages ‘functional’?&lt;/p&gt;
&lt;p&gt;No. Because then the term would be meaningless.&lt;/p&gt;
&lt;p&gt;So what can we give as a “jobbing programmer’s definition of a
functional programming language”?&lt;/p&gt;
&lt;p&gt;A functional programming language is one that supports and encourages
programming without side-effects.&lt;/p&gt;
&lt;p&gt;Or more specifically: A functional language actively helps you
eliminate side-effects wherever possible, and tightly control them
wherever it’s not.&lt;/p&gt;
&lt;p&gt;Or more dramatically: A functional language is actively hostile to
side-effects. Side-effects are complexity and complexity is bugs and
bugs are the devil. A functional language will help you be hostile to
side-effects too. Together you will beat them into submission.&lt;/p&gt;
&lt;h2 id=&quot;is-that-it&quot;&gt;Is That It?&lt;/h2&gt;
&lt;p&gt;Yes. There are a couple of subtleties - things you probably never
thought of as a hidden input before, but that’s the essence. But start
building software with the perspective of “side-effects are the first
enemy” and it will change everything you know about programming. &lt;a href=&quot;https://blog.jenkster.com/2015/12/which-programming-languages-are-functional.html&quot;&gt;Join me for part two&lt;/a&gt;, in which we take an awareness of side-effects, and
functional programming, and fire a scattergun over the programming
landscape.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;This post comes out of a couple of discussions about the nature of
functional programming. Particularly a chat with &lt;a href=&quot;https://twitter.com/sleepyfox&quot;&gt;Sleepyfox&lt;/a&gt; discussing
whether JavaScript could be considered a functional programming
language, with the right libraries. My answer was an instinctive no,
but thinking through /why/ lead me along a very fruitful chain of
thought.&lt;/p&gt;
&lt;p&gt;Hat tip to &lt;a href=&quot;https://twitter.com/jarohen&quot;&gt;James Henderson&lt;/a&gt;, which whom I have bounced around
many fruitful functional ideas this year.&lt;/p&gt;
&lt;p&gt;And thanks to &lt;a href=&quot;https://twitter.com/malcolmsparks&quot;&gt;Malcolm Sparks&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/llaisdy&quot;&gt;Ivan Uemlianin&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/jclermont&quot;&gt;Joel Clermont&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/katyemoe&quot;&gt;Katy Moe&lt;/a&gt;
and my homophonic-doppleganger &lt;a href=&quot;https://twitter.com/cdpjenkins&quot;&gt;Chris Jenkins&lt;/a&gt; for proofreading &amp;amp;
suggestions.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Although Java tries really hard. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Which Programming Languages Are Functional?</title><link>https://blog.jenkster.com/2015/12/which-programming-languages-are-functional.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/12/which-programming-languages-are-functional.html</guid><pubDate>Tue, 29 Dec 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;In part one of this post&lt;/a&gt;, I defined functional programming not from an
academic perspective, or a marketing one, but in a way that will make
sense to a jobbing programmer. More importantly, I hope, I defined
what side-effects are in a way that makes it easy for a jobbing
programmer to spot them before they spiral out of control.&lt;/p&gt;
&lt;p&gt;Now, let’s take a look at functional programming languages in the real
world…&lt;/p&gt;
&lt;h2 id=&quot;pot-shots-across-the-programming-landscape&quot;&gt;Pot Shots Across the Programming Landscape&lt;/h2&gt;
&lt;p&gt;Armed with the ability to spot side-effects, we can now look at a
given function and spot hidden complexity. And armed with some
real-world definitions of FP, we can now survey the programming world
and fire some new insights in practically every direction…&lt;/p&gt;
&lt;h3 id=&quot;functional-programming-is-not&quot;&gt;Functional Programming is not…&lt;/h3&gt;
&lt;h4 id=&quot;its-not-map-and-reduce&quot;&gt;It’s not &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;reduce&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Even though you’ll see these functions in every functional language,
it’s not what makes the language functional. It’s just something that
crops up nearly every time you try to take the side-effects out of
processing sequences of things.&lt;/p&gt;
&lt;h4 id=&quot;its-not-lambda-functions&quot;&gt;It’s not lambda functions&lt;/h4&gt;
&lt;p&gt;Again, you’ll probably see first-class functions in every FP
language. But it’s something that naturally emerges when you start
building a language that avoids side-effects. It’s an enabler, but not
the root cause.&lt;/p&gt;
&lt;h4 id=&quot;its-not-types&quot;&gt;It’s not types&lt;/h4&gt;
&lt;p&gt;Static type checking is a very useful tool, but it’s not a
pre-requisite for FP. Lisp is the oldest functional programming
language, and the oldest dynamic language.&lt;/p&gt;
&lt;p&gt;Static types can be very useful though. Haskell uses its type system
beautifully in the attack on side-effects. But they aren’t the
ingredient that makes or breaks a functional language.&lt;/p&gt;
&lt;p&gt;Say it long, say it loud, functional programming is about side-effects.&lt;/p&gt;
&lt;p&gt;(And side-causes, of course).&lt;/p&gt;
&lt;h2 id=&quot;what-does-this-mean-for-languages&quot;&gt;What Does This Mean For Languages?&lt;/h2&gt;
&lt;h3 id=&quot;javascript-is-not-a-functional-programming-language&quot;&gt;JavaScript is not a Functional Programming Language&lt;/h3&gt;
&lt;p&gt;Functional languages help you eliminate side-effects where you can,
and control them where you can’t. JavaScript doesn’t meet this
criteria. In fact, it’s easy to spot places where JavaScript actively
&lt;em&gt;encourages&lt;/em&gt; side-effects.&lt;/p&gt;
&lt;p&gt;The easiest target is &lt;code&gt;this&lt;/code&gt;. The hidden input that’s in every
function. What’s particularly magical about &lt;code&gt;this&lt;/code&gt; is how freely its
meaning changes. Even expert JavaScript programmers have trouble
keeping track of what &lt;code&gt;this&lt;/code&gt; currently refers to. From a functional
point of view, the fact that it’s magically available at all is a
design smell.&lt;/p&gt;
&lt;p&gt;While you can certainly load FP &lt;em&gt;libraries&lt;/em&gt; (Immutable.js, for
instance) into JavaScript, and that makes programming in a functional
style easier, it doesn’t change the nature of the language itself.&lt;/p&gt;
&lt;p&gt;(By the way, if you like the functional libraries that are gaining
popularity in JavaScript land, imagine how much you’d like a whole
language that supported the functional style.)&lt;/p&gt;
&lt;h3 id=&quot;java-is-not-a-functional-programming-language&quot;&gt;Java is not a Functional Programming Language&lt;/h3&gt;
&lt;p&gt;Java is most definitely not a functional language. The addition of
lambdas in Java 1.8 does nothing to change that. Java stands in stark
opposition to functional programming. It’s core design principal says
that code should be organised as a series of localised side-effects -
methods that depend on and change the local state of an object.&lt;/p&gt;
&lt;p&gt;In fact, Java is hostile to functional programming. If you write Java
code that has no side-effects, that doesn’t read or change the local
object’s state, you’ll be called a Bad Programmer. That’s not how Java
is written. Your side-effect free code will be peppered with &lt;code&gt;static&lt;/code&gt;
keywords, and they’ll frown and drive you out of town.&lt;/p&gt;
&lt;p&gt;I’m not saying Java is wrong. (Well, okay, I am.) But the point is it
takes a completely different view of side-effects. Java thinks that
localised side-effects are cornerstone of good code; FP thinks they’re
the devil.&lt;/p&gt;
&lt;p&gt;You could look at that from a slightly different angle. You could see
both Java and FP as responses to the problem of side-effects. Both
models recognise side-effects as a problem, and respond
differently. OO’s answer is, “contain them within boundaries called
‘objects’,” whereas FP’s answer is, “eliminate them”. Unfortunately,
in practice Java doesn’t just try to encapsulate side-effects; it
mandates them. If you’re not creating side-effects, in the form of
stateful objects, then you’re a Bad Java Programmer. People actually
get fired for writing &lt;code&gt;static&lt;/code&gt; too often.&lt;/p&gt;
&lt;h3 id=&quot;scala-has-a-big-task-on-its-hands&quot;&gt;Scala Has a Big Task on its Hands&lt;/h3&gt;
&lt;p&gt;Seen in this light, Scala is a very challenging proposition. If its
goal is to unify the two worlds of OO and FP, then through the lens of
side-effects we see it as trying to bridge the gap between
“Side-Effects Mandatory” and “Side-Effects Forbidden&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;”. They’re
such opposite views that I’m not sure they can be reconciled. You
certainly can’t unify the two just by making objects support the &lt;code&gt;map&lt;/code&gt;
function. You’ll need to go deeper and reconcile the conflict between
the two opposing stances on side-effects.&lt;/p&gt;
&lt;p&gt;I’ll leave you to judge if Scala succeeds in such a
reconciliation. But if I were in charge of Scala’s marketing I’d sell
it as a &lt;em&gt;gradual&lt;/em&gt; move away from the side-effecting world of Java, to
the pure world of FP. Instead of unifying them, it could be a bridge
away. Indeed, many people see it that way in practice.&lt;/p&gt;
&lt;h3 id=&quot;clojure&quot;&gt;Clojure&lt;/h3&gt;
&lt;p&gt;Clojure takes an interesting stance on side-effects. Its creator, Rich
Hickey, has said that Clojure is about “80% functional”. I think I can
clarify why that is. From the outset, Clojure was designed to deal
with one specific kind of side-effect: Time.&lt;/p&gt;
&lt;p&gt;To illustrate this, here’s a Java joke for you:&lt;/p&gt;
&lt;p&gt;#+BEGIN_QUOTE&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What’s 5 plus 2?&lt;/li&gt;
&lt;li&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Correct. What’s 5 plus 3?&lt;/li&gt;
&lt;li&gt;8&lt;/li&gt;
&lt;li&gt;Nope. It’s 10, because we turned 5 into 7, remember?
#+END_QUOTE&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Okay, it’s not a great joke. But the point is, in Javaland, values
don’t stay still. We might legitimately take something that represents
a five, call a function, and find that it’s no longer a
five. Mathematics says that five never changes - we can call a
function that gives us a &lt;em&gt;new&lt;/em&gt; value, but we can never affect the
nature of five itself. Java says values change all the time, and as
long as they’re wrapped in object boundaries that’s okay.&lt;/p&gt;
&lt;p&gt;The integer case may seem trivial, but the effect is amplified when we
look at larger values. Remember &lt;code&gt;InboxQueue&lt;/code&gt; from &lt;a href=&quot;https://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;part 1&lt;/a&gt;? The state of
&lt;code&gt;InboxQueue&lt;/code&gt; is a value that changes over time. We can say that Time
is a side-cause to the meaning of &lt;code&gt;InboxQueue&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Clojure focuses ferociously on the side-cause of Time. Rich Hickey’s
insight&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; is that the hidden effect of time means we can’t rely on
values to stay put; and if we can’t rely on that, we can’t rely on our
functions’ inputs, and so we can’t rely on anything to behave
predictably or repeatably. If even values have side-effects, then
&lt;em&gt;everything&lt;/em&gt; has side-effects. If values aren’t pure, nothing in our
programs can be pure.&lt;/p&gt;
&lt;p&gt;So Clojure takes a sword to time. All its values are immutable
(unchanging over time) by default. If you need a changing value,
Clojure provides wrappers around unchanging values, and those wrappers
are subject to heavy constraints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You must opt-in to changing (mutable) values by using a wrapper.&lt;/li&gt;
&lt;li&gt;You cannot &lt;em&gt;accidentally&lt;/em&gt; create a mutable value. You must always use
guards in the language explicitly flag potential side-effects.&lt;/li&gt;
&lt;li&gt;You cannot unwittingly consume a mutable-value. You must always use
guards in the language explicitly acknowledge the risk of
side-effects.&lt;/li&gt;
&lt;li&gt;When you open a mutable-value wrapper, the thing you get back is
immutable again. You can easily get back out of the time-dependent
world and back into the pure one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;With respect to time&lt;/em&gt;, Clojure is a great example of a functional
programming language. The language is deeply hostile to the
side-effect of time. It eliminates it wherever it can, by default, and
where you feel you must have the side-effect, it helps you tightly
control it so it doesn’t spill into the rest of your program.&lt;/p&gt;
&lt;h3 id=&quot;haskell&quot;&gt;Haskell&lt;/h3&gt;
&lt;p&gt;If Clojure is hostile to time, Haskell is just plain hostile. Haskell
really hates side-effects, and puts a large amount of effort into
controlling them.&lt;/p&gt;
&lt;p&gt;One of the interesting ways Haskell fights side-effects is with
types. It pushes all side-effects up into the type-system. For
example, imagine you’ve got a &lt;code&gt;getPerson&lt;/code&gt; function. In Haskell it
might look like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;getPerson&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; UUID&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Database&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Person&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can read that as, “takes a &lt;code&gt;UUID&lt;/code&gt; and returns a &lt;code&gt;Person&lt;/code&gt; &lt;em&gt;in the
context of&lt;/em&gt; a &lt;code&gt;Database&lt;/code&gt;”. This is interesting - you can look at the
type signature of a Haskell function and know for certain which
side-effects are involved. And which aren’t. You can also make
guarantees like, “this function won’t access the filesystem, because
it’s not declared that kind of side-effect.” Tight control&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Equally important, you can look at a function like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;formatName&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Person&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…and know that this just takes a &lt;code&gt;Person&lt;/code&gt; and returns a
&lt;code&gt;String&lt;/code&gt;. Nothing else, because if there were side-effects you’d see
them locked into the type signature.&lt;/p&gt;
&lt;p&gt;But perhaps most interesting of all, is this example:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;formatName&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Person&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Database&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The signature tells us that this version of &lt;code&gt;formatName&lt;/code&gt; involves
database-related side-effects. What the hell? Why does &lt;code&gt;formatName&lt;/code&gt;
need the database? You mean I’m going to need to set-up and mock-out
a database just to test a name-formatter? That’s really weird.&lt;/p&gt;
&lt;p&gt;Just by looking at this function signature, I can see something’s
wrong with the design. I don’t need to look at the code, I can smell a
rat just from the overview. That’s magic.&lt;/p&gt;
&lt;p&gt;Let’s just briefly compare that with the Java signature:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; formatName&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; person) {..}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which Haskell-version is that equivalent to? Without seeing the body
of the function, you have no way of knowing. It may be the pure
version, it may access the database. Or it may delete the filesystem
and return, &lt;code&gt;&quot;screw you boss!&quot;&lt;/code&gt;. The type signature tells you very
little about what’s going on, or what the surface area of the function
is.&lt;/p&gt;
&lt;p&gt;Haskell’s type signatures, in contrast, tell you a great deal about
the design. And because they’re checked by the compiler, they tell you
things you &lt;em&gt;know&lt;/em&gt; to be true. And that means they make great
architectural tools. They surface design-smells at a very high level,
And they also surface patterns of coding too. I’m going to keep the
words ‘functor’ and ‘monad’ out of this post, but I will say that
high-level software patterns begin with high-level analysis, and
high-level analysis is made &lt;em&gt;much&lt;/em&gt; easier when you have a high-level
&lt;em&gt;notation&lt;/em&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id=&quot;perl&quot;&gt;Perl&lt;/h3&gt;
&lt;p&gt;Perl deserves a mention here in any discussion of side-effects. It has
a magic argument, &lt;code&gt;$_&lt;/code&gt;, which means something like, “the return value
of the previous call&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;.” It gets used and/or changed by many of
the core library functions, implicitly. As far as I know this gives
Perl the distinction of being the only language where one global
side-effect is considered a core feature.&lt;/p&gt;
&lt;h3 id=&quot;python&quot;&gt;Python&lt;/h3&gt;
&lt;p&gt;Let’s take a quick look at a fundamental side-effecting pattern in Java:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; getName&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BD93F9;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;.name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How would we purify this call? Well, &lt;code&gt;this&lt;/code&gt; is the hidden input, so
all we have to do is lift it up to an argument:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; getName&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#BD93F9;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BD93F9;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;.name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;getName&lt;/code&gt; is a pure function. It’s noteworthy that Python adopts
this second pattern by default. In python, all object methods take
&lt;code&gt;this&lt;/code&gt; as the first argument, except by convention they call it
&lt;code&gt;self&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;python&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; getName&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9;font-style:italic&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9;font-style:italic&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;.name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0020/&quot;&gt;Explicit is better than implicit&lt;/a&gt; indeed.&lt;/p&gt;
&lt;h3 id=&quot;mocking&quot;&gt;Mocking&lt;/h3&gt;
&lt;p&gt;Mocking frameworks usually do two things.&lt;/p&gt;
&lt;p&gt;The first is they help you set up value objects to act as inputs. The
harder your language makes it to set up complex values, the more
useful you’ll find this. But that’s an aside.&lt;/p&gt;
&lt;p&gt;The second is more interesting in this discussion - they help you set
up the right side-causes to the function under test, and track that
the right side-effects have occurred after the test.&lt;/p&gt;
&lt;p&gt;Seen through the lens of side-effects, mocks are a flag that your code
is impure, and in the functional programmer’s eye, proof that
something is wrong. Instead of downloading a library to help us check
the iceberg is intact, we should be sailing around it.&lt;/p&gt;
&lt;p&gt;A hardcore TDD/Java guy once asked me how you do mocking in
Clojure. The answer is, we usually don’t. We usually see it as a sign
we need to refactor our code.&lt;/p&gt;
&lt;h2 id=&quot;design-smells-or-the-scent-of-nothingness&quot;&gt;Design Smells (or The Scent Of Nothingness)&lt;/h2&gt;
&lt;p&gt;If there were an &lt;a href=&quot;https://en.wikipedia.org/wiki/I-Spy_(Michelin)&quot;&gt;I-Spy&lt;/a&gt; book of side-effects, the two easiest targets
to spot would be functions that take no arguments, and functions that
return no value.&lt;/p&gt;
&lt;h3 id=&quot;no-arguments-signal-side-causes&quot;&gt;No Arguments Signal Side-Causes&lt;/h3&gt;
&lt;p&gt;Whenever you see a function with no arguments, one of
two things are true: Either it always returns exactly the same value,
or it’s getting its inputs from elsewhere (ie. it has side-causes).&lt;/p&gt;
&lt;p&gt;For example, this function must always, always return the same
integer (or it has side-causes):&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;no-return-value-signals-side-effects&quot;&gt;No Return Value Signals Side-Effects&lt;/h3&gt;
&lt;p&gt;And whenever you see a function with no return value, then either it
has side-effects, or there was no point calling it:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(...) {...}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;According to that function signature, there is absolutely no reason to
call this function. It doesn’t give you anything. The only reason to
call it is for the magical side-effects it promises it will silently
cause.&lt;/p&gt;
&lt;h2 id=&quot;summary--conclusion-y-thing&quot;&gt;Summary / Conclusion-y Thing&lt;/h2&gt;
&lt;p&gt;A real, intuitive awareness of side-effects will change the way you
look at coding. It will change everything from how you look at
individual functions, right up to overall systems-architecture. It
will change the way you look at programming languages, tools and
techniques. It changes everything. Go kill a side-effect today…&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Yes, I’m conflating OO and Java. In the context of Scala I think it’s fair to equate the two. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;One of them! &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;PureScript takes this idea further, and is worth looking into. &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;I’ve had some great Clojure design discussions where we’ve used Haskell signatures to explain ourselves, verify the consistency of the design, and to summarise our conclusions. Yes, Clojure discussions. Haskell’s notation has a value that extends far beyond the language. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;See &lt;code&gt;man perlvar&lt;/code&gt; for the exact definition. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Quote of the Week - Doug Crockford</title><link>https://blog.jenkster.com/2015/10/quote-of-the-week-doug-crockford.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/10/quote-of-the-week-doug-crockford.html</guid><pubDate>Fri, 30 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I’m now thinking I’ve got two completely different types of objects:
those containing only data, which are things I share with JSON; and
things containing only methods, which are things I can share with
applications.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PSGEjv3Tqo0&quot;&gt;Doug Crockford - The Better Parts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think Doug Crockford’s great, but it does seem like he’s getting to
Functional Programming by the absolute slowest route possible.&lt;/p&gt;
</content:encoded></item><item><title>Geocoding With Elm and ArcGIS, Part 3</title><link>https://blog.jenkster.com/2015/10/geocoding-with-elm-and-arcgis-part-3.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/10/geocoding-with-elm-and-arcgis-part-3.html</guid><pubDate>Wed, 07 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After &lt;a href=&quot;http://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-1.html&quot;&gt;part 1&lt;/a&gt; and
&lt;a href=&quot;http://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-2.html&quot;&gt;part 2&lt;/a&gt;, I thought I was finished with this feature, but
&lt;a href=&quot;https://disqus.com/by/ariaroooefe/&quot;&gt;Ariarooo Efe&lt;/a&gt;
rightly &lt;a href=&quot;http://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-1.html#comment-2293898738&quot;&gt;comments&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[in] the online demo of the app, if there are no results the user isn’t told anything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This feedback is trivial to add, so let’s just see what quick work Elm
makes of it.&lt;/p&gt;
&lt;h2 id=&quot;the-model&quot;&gt;The Model&lt;/h2&gt;
&lt;p&gt;Recapping on the model of the app:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type alias Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  {...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ,places &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Maybe&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Place&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ...}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-1.html&quot;&gt;Part 1&lt;/a&gt; explains how &lt;code&gt;places&lt;/code&gt; models the data we’re loading, and makes
a clear, type-checked distinction between these cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We haven’t loaded any data yet.&lt;/li&gt;
&lt;li&gt;We have loaded data, but that failed.&lt;/li&gt;
&lt;li&gt;We’ve loaded data and it’s available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What it also gives us, which in many frontend frameworks we might not
get, is a very clear distinction of, “we loaded some data and it was
empty”. If &lt;code&gt;places&lt;/code&gt; is an empty list, there’s no confusion - it
doesn’t mean “not asked” or “there was an error”, it only means there
are zero results.&lt;/p&gt;
&lt;p&gt;Armed with a correct data model, we’re going to find the rest easy…&lt;/p&gt;
&lt;h2 id=&quot;the-view&quot;&gt;The View&lt;/h2&gt;
&lt;p&gt;In the case of “no results”, the value of places will be &lt;code&gt;Just (Ok [])&lt;/code&gt;. That is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Just ...&lt;/code&gt; - we’ve got some data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ok ...&lt;/code&gt; - we got it successfully.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[]&lt;/code&gt; - it was the empty list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can update our rootView to add an extra case in:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rootView&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Address&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Action&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Maybe&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; LatLng&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rootView&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; uiChannel currentLocation model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  div []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      ,&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;places &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;        Nothing&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; span [] []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;        Just&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; err) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; div [class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;alert alert-danger&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] [text &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;|&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; toString err]&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:#6272A4&quot;&gt;        -- This is the new case:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;        Just&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; []) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; div [class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;alert alert-warning&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] [text &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;No results found.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#BD93F9&quot;&gt;        Just&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; resultsList uiChannel currentLocation xs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;      ...&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Note that we put the more specific match &lt;code&gt;Just (Ok [])&lt;/code&gt; before the
more general one &lt;code&gt;Just (Ok xs)&lt;/code&gt;, because patterns are checked in order
and the first one wins.)&lt;/p&gt;
&lt;h2 id=&quot;were-done&quot;&gt;We’re done.&lt;/h2&gt;
&lt;p&gt;Yup, there’s almost no work to do. Why? Because we had a good data
model to begin with - one that was clearly defined and correctly
represented the different states our app could be in.&lt;/p&gt;
&lt;p&gt;Say it long, say it loud, programming begins with data-modeling.&lt;/p&gt;
&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;
&lt;p&gt;The whole app is a little larger, and I’ll be writing up other
pieces. In the meantime, you can see the geocoding part in action by
&lt;a href=&quot;http://krisajenkins.github.io/beeline-demo/&quot;&gt;playing with the finished hackday app here&lt;/a&gt; and then &lt;a href=&quot;https://github.com/krisajenkins/beeline-demo&quot;&gt;read the source code&lt;/a&gt; to learn more.&lt;/p&gt;
</content:encoded></item><item><title>Geocoding With Elm and ArcGIS, Part 1</title><link>https://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-1.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-1.html</guid><pubDate>Fri, 25 Sep 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently &lt;a href=&quot;http://devpost.com/software/beeline-demo/&quot;&gt;wrote a navigation app for a hack day&lt;/a&gt;, and since it’s
written in Elm, and there aren’t enough blog posts about Elm, I
thought I’d break down some of the pieces. Here’s a nice juicy one:
letting the user search for a location, and turning that into latitude
&amp;amp; longitude - ‘geocoding’.&lt;/p&gt;
&lt;h1 id=&quot;the-spec&quot;&gt;The Spec&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;We need an input box you can type your search into.&lt;/li&gt;
&lt;li&gt;When you submit, we fetch a list of possible matches from &lt;a href=&quot;https://www.arcgis.com/features/&quot;&gt;ArcGIS&lt;/a&gt;
(the company that sponsored the hack day in question, and who have a
Geocoding API).&lt;/li&gt;
&lt;li&gt;We need to display those matches.&lt;/li&gt;
&lt;li&gt;You can choose one. (A choice which will cause something else to happen. Something that’s outside the scope of this post).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see how Elm tackles it…&lt;/p&gt;
&lt;h1 id=&quot;the-implementation&quot;&gt;The Implementation&lt;/h1&gt;
&lt;p&gt;Every Elm app breaks down into a few simple parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A data structure representing the state of the world.&lt;/li&gt;
&lt;li&gt;A set of possible events that can occur.&lt;/li&gt;
&lt;li&gt;An event handler: a function that takes the current state of the world, and one event,
and returns the new state of the world, plus any side-effects that
must occur.&lt;/li&gt;
&lt;li&gt;A function that can display the current state of the world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s break those pieces down:&lt;/p&gt;
&lt;h2 id=&quot;model&quot;&gt;Model&lt;/h2&gt;
&lt;p&gt;Our state of the world, our &lt;code&gt;Model&lt;/code&gt;, will need to capture the contents
of the form, the list of matching places, and the chosen
place. And for UX-sweetness we’ll add in a loading-flag, so we can
disable the form while we’re fetching results.&lt;/p&gt;
&lt;p&gt;In Elm-land we’ll model this as a record. First we’ll need to define
the type of a search result, which I’ll call a &lt;code&gt;Place&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type alias Place&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  {address: &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ,latitude: &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Float&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ,longitude: &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Float&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can define the whole app state:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  type alias &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    {searchTerm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    ,loading &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    ,places &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Maybe&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Place&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    ,chosenPlace &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Maybe&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Place&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;chosenPlace&lt;/code&gt; is a &lt;code&gt;Place&lt;/code&gt;, of course, but initially no-one’s chosen
anything, so we’ll wrap it in a &lt;code&gt;Maybe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;places&lt;/code&gt; is the trickiest type to read here. &lt;code&gt;Maybe (Result Error (List Place))&lt;/code&gt; is saying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Maybe&lt;/code&gt; We may or may not have…&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Result Error ...&lt;/code&gt; the result of a request, which may be failure, or may
be…&lt;/li&gt;
&lt;li&gt;&lt;code&gt;List Place&lt;/code&gt; a list of places.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it. That’s the state of the world, the whole state of the
world, and will fully describe the state of the world for the lifetime
of the app&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;action&quot;&gt;Action&lt;/h2&gt;
&lt;p&gt;By convention, Elm describes all events that could occur in the system
with an &lt;code&gt;Action&lt;/code&gt; type. What are the events that can occur in our app?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The user types something, changing our search term.&lt;/li&gt;
&lt;li&gt;The user hits submit.&lt;/li&gt;
&lt;li&gt;The internets give us a list of places.&lt;/li&gt;
&lt;li&gt;The user chooses a place.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That translates into a union type of:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;type Action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ChangeTerm&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Submit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; PlacesResponse&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Place&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ChoosePlace&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Place&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For those unfamiliar with the syntax, this is saying that an &lt;code&gt;Action&lt;/code&gt;
can be any one, and &lt;em&gt;only one&lt;/em&gt; of the values that follow. Some, like
&lt;code&gt;ChangeTerm&lt;/code&gt; carry a payload value of &lt;code&gt;String&lt;/code&gt;, some like &lt;code&gt;Submit&lt;/code&gt; are
just markers.&lt;/p&gt;
&lt;p&gt;That’s it. Those are the events, all the events, and &lt;code&gt;Action&lt;/code&gt; fully
describes every event that can occur for the lifetime of the
app&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;update&quot;&gt;update&lt;/h2&gt;
&lt;p&gt;The next piece we need is an event handler, which we call
&lt;code&gt;update&lt;/code&gt;. Let’s start with an easy, but incomplete version:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Action&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Effects&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Action&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; action model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;action &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    ChangeTerm&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ({model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; term &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s}, &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Effects&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;none)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is saying, “if you give me an &lt;code&gt;Action&lt;/code&gt; and the current &lt;code&gt;Model&lt;/code&gt; of
the world, I can process that &lt;code&gt;Action&lt;/code&gt; and give you the new &lt;code&gt;Model&lt;/code&gt;,
plus any side-effects that need to occur (like kicking off an AJAX
request).”&lt;/p&gt;
&lt;p&gt;In this case, we’re just handling the “user types into the input box”
case, to get used to the syntax. We unpack the string that the
&lt;code&gt;ChangeTerm&lt;/code&gt; action holds, and update the model with it. This case
causes no side-effects, so we say that explicity with &lt;code&gt;Effects.none&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other easy event is “user chooses a place”. Let’s add that into our
&lt;code&gt;update&lt;/code&gt; function’s &lt;code&gt;case&lt;/code&gt; statement:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;action &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    ChoosePlace&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ({model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; chosenPlace &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Just&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; p}, &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Effects&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;none)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The next up is submit:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;action &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    Submit&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ({model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; loading &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; True&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              ,&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Effects&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;map &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;PlacesResponse&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (findPlaces term))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s more interesting. We’re kicking off a search. In the model, we
set the &lt;code&gt;loading&lt;/code&gt; flag. This is purely for UX. Alongside that, for the
first time, we have an interesting side-effect. We’re calling
&lt;code&gt;findPlaces&lt;/code&gt; to create a request, and then using &lt;code&gt;map&lt;/code&gt; to wrap the
response in a &lt;code&gt;PlacesResponse&lt;/code&gt; &lt;code&gt;Action&lt;/code&gt;, so that we’ll know know what
kind event it is when we come to process it later.&lt;/p&gt;
&lt;p&gt;We’ll see how &lt;code&gt;findPlaces&lt;/code&gt; is defined later. For now, let’s finish off
&lt;code&gt;update&lt;/code&gt; by defining how to handle the response:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  case &lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;action &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    PlacesResponse&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ({model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; places &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Just&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; xs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                 , loading &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; False&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                         , &lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Effects&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;none)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we get a response, switch that &lt;code&gt;loading&lt;/code&gt; flag off, and store the
places.&lt;/p&gt;
&lt;p&gt;That’s it. That’s the business logic, all the business-logic, and fully describes
how every event changes the state of the world for the lifetime of the app&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pause&quot;&gt;Pause&lt;/h2&gt;
&lt;p&gt;This seems like a lot, so let’s take a breather. We have events. We
have a state of the world. We have a function that moves the state of
the world forward.&lt;/p&gt;
&lt;p&gt;It’s nice that the events follow pretty directly from asking, “What can the user do?”&lt;/p&gt;
&lt;p&gt;It’s also nice that once we’ve describe how to handle each event,
we’re done with business logic.&lt;/p&gt;
&lt;p&gt;In the next release of Elm, the compiler will be able to warn you if
you miss out any event handlers&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, and that will be very nice indeed.&lt;/p&gt;
&lt;p&gt;So now we just needed to describe that &lt;code&gt;findPlaces&lt;/code&gt; function, and
worry about the UI. To do that we’ll need to talk about &lt;code&gt;Effects&lt;/code&gt;,
JSON-parsing and HTML-rending.&lt;/p&gt;
&lt;p&gt;Why don’t you go and make a cup of tea&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; and &lt;a href=&quot;https://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-2.html&quot;&gt;join me for part two&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the meantime, you can &lt;a href=&quot;http://krisajenkins.github.io/beeline-demo/&quot;&gt;play with the finished hackday app here&lt;/a&gt; and
&lt;a href=&quot;https://github.com/krisajenkins/beeline-demo&quot;&gt;read the source code&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Good luck trying to say something that definitive in an Angular app. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Good luck trying to say something that definitive in an Angular app. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Good luck trying to say…oh, you get the point. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;And quickly, at that. Elm’s compiler is impressively fast. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;Make it /properly/ mind. &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Geocoding With Elm and ArcGIS, Part 2</title><link>https://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-2.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-2.html</guid><pubDate>Fri, 25 Sep 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Following on from &lt;a href=&quot;https://blog.jenkster.com/2015/09/geocoding-with-elm-and-arcgis-part-1.html&quot;&gt;part 1&lt;/a&gt;, we had completed our description of the app,
and the event handlers, and we just needed to worry about making an
AJAX request, decoding the response, and rendering the HTML.&lt;/p&gt;
&lt;p&gt;Just. :-)&lt;/p&gt;
&lt;h2 id=&quot;ajax&quot;&gt;AJAX&lt;/h2&gt;
&lt;p&gt;ArcGIS has a nice API for geocoding&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. We send a GET with the term
as a query parameter, we get back some JSON for places in the world
that match that search term. It’s easy to use.&lt;/p&gt;
&lt;p&gt;For our wiring, we have a search term, and we want to generate the
side-effect that eventually returns a list of places. Remembering that
that side-effect may fail with an HTTP error, we get this type
signature:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;findPlaces&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Effects&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Place&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To read the actual implementation you’ll need to know that &lt;code&gt;|&amp;gt;&lt;/code&gt; is an
operator that basically reads as a unix pipe &lt;code&gt;|&lt;/code&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;- take the results of
the last function and pass them in as the input to the next function:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;findPlaces&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; term &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;http://geocode.arcgis.com/arcgis/rest/services&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ++&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;/World/GeocodeServer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    ++&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;/findAddressCandidates?f=json&amp;amp;singleLine=&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ++&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Http&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;uriEncode term&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Http&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;get decodePlaces&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;toResult&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Effects&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;task&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s a lot of type-wrangling in there, but the noteworthy bit is
that &lt;code&gt;Http.get&lt;/code&gt; takes a JSON-decoder as its first argument, which will
fire if the get request was successful.&lt;/p&gt;
&lt;h2 id=&quot;json&quot;&gt;JSON&lt;/h2&gt;
&lt;p&gt;Let’s look at &lt;a href=&quot;http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?f=json&amp;amp;singleLine=royal+festival+hall&quot;&gt;a sample response from the API&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;json&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;spatialReference&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;wkid&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 4326&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;latestWkid&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 4326&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;candidates&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Royal Festival Hall&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -0.11599726799954624&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 51.50532882800047&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;score&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;attributes&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;extent&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;xmin&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -0.120998&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;ymin&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 51.500329&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;xmax&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -0.110998&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;ymax&lt;/span&gt;&lt;span style=&quot;color:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 51.510329&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For JSON-decoding I always pull in [JSON extras](&lt;a href=&quot;https://twitter.com/circuithub&quot;&gt;https://twitter.com/circuithub&lt;/a&gt;][CircuitHub]]’s [[&lt;a href=&quot;http://package.elm-lang.org/packages/circuithub/elm-json-extra/latest/&quot;&gt;http://package.elm-lang.org/packages/circuithub/elm-json-extra/latest/&lt;/a&gt;), so let’s
import those:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Json&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Decode&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Json&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (..)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Json&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Decode&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Extra&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; exposing&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the parsing is reduced to two functions, which make use of &lt;code&gt;:=&lt;/code&gt; to
access a property and &lt;code&gt;at&lt;/code&gt; to walk a nested path down the tree.&lt;/p&gt;
&lt;h3 id=&quot;decode-one-place&quot;&gt;Decode one &lt;code&gt;Place&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;decodePlace&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Decoder&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Place&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;decodePlace&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Place&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  `map`   (&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  `apply` (at [&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] float)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  `apply` (at [&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] float)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;decode-the-list-of-places&quot;&gt;Decode the &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;Places&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;decodePlaces&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Decoder&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Place&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;decodePlaces&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  at [&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;candidates&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] (list decodePlace)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At the actual hackday I wrote this code, I found this kind of thing
very fast to write. You’d think having to write a parser for JSON
before you can use it would slow you down, but certainly on that day I
found it sped things up: The first pass was slower, sure, but as I
built out the app and discovered that my initial assumptions about the
schema were wrong, having the compiler tell me all the places my
assumptions were wrong saved a lot of time.&lt;/p&gt;
&lt;h2 id=&quot;right-thats-it-were-done&quot;&gt;Right, That’s It, We’re Done&lt;/h2&gt;
&lt;p&gt;Oh wait, no. We haven’t actually displayed anything to the user yet.&lt;/p&gt;
&lt;h2 id=&quot;rendering&quot;&gt;Rendering&lt;/h2&gt;
&lt;p&gt;So the last piece we need is a rendering function. HTML gets huge, so
I’ll just focus on an illustrative piece and &lt;a href=&quot;https://github.com/krisajenkins/beeline-demo/blob/master/src/FindAddress/View.elm&quot;&gt;point you to the source&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most HTML-rendering functions in Elm have essentially the same
signature. You might expect it to be as simple as:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;searchForm&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…but it’s &lt;em&gt;slightly&lt;/em&gt; more complicated than that, because DOM.&lt;/p&gt;
&lt;p&gt;It’s not enough to just generate HTML. We also need a way for user
clicks and keypresses to generate events (as Elm &lt;code&gt;Actions&lt;/code&gt;). So the
most common type signature is some variant of:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;searchForm&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Address&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Action&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That &lt;code&gt;Address Action&lt;/code&gt; will give us a way to make &lt;code&gt;onClick&lt;/code&gt; events
generate a &lt;code&gt;Action&lt;/code&gt;, without polluting our rendering code with
business logic. It’s a channel, queue, or postbox where we can send
event data&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;So, let’s look at our search box. &lt;a href=&quot;https://blog.jenkster.com/2015/09/responsive-youtube-videos-with-elm.html&quot;&gt;(Here’s a primer for reading Elm’s HTML syntax.)&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;searchForm&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; address model &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  div [class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;form-group&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      [input [class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;form-control&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             ,autofocus &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             ,on &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;keyup&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  targetValue (message address &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; TermChange&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             ,type&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;&apos; &quot;text&quot;] []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;      ,hr [] []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;      ,button [class &quot;btn btn-lg btn-block btn-success&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;              ,disabled model.loading&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;              ,type&apos;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              ,onClick address &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Submit&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              [text &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Search&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s look at a few of those pieces:&lt;/p&gt;
&lt;h3 id=&quot;onclick&quot;&gt;onClick&lt;/h3&gt;
&lt;p&gt;This makes a button click turn into a &lt;code&gt;Submit&lt;/code&gt; action:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  onClick address &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;Submit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;disabled&quot;&gt;disabled&lt;/h3&gt;
&lt;p&gt;Here we disable the button when there’s a load in-flight. It’s an easy
way to give the user some feedback that the click actually caused something:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  disabled model&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;loading&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…recall that &lt;code&gt;model.loading&lt;/code&gt; is handled in the &lt;code&gt;update&lt;/code&gt;
function. The button is not made responsible for tracking which AJAX
requests are in-flight, as that would be an insane abuse of the single
responsibility principal. It’s just a button that displays how it’s told.&lt;/p&gt;
&lt;h3 id=&quot;autofocus&quot;&gt;autofocus&lt;/h3&gt;
&lt;p&gt;For another UX nicety, it’s trivial to make this form field capture the
cursor when the page renders:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  autofocus &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;on&quot;&gt;on&lt;/h3&gt;
&lt;p&gt;The only really juicy part of this code is the input &lt;code&gt;keyup&lt;/code&gt; event
handler. It’s a little more complex because it needs to refer to
the value of the event target. It’s also interesting because it shows
how you can handle any arbitrary event type:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  on &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;keyup&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  targetValue (message address &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; TermChange&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Whenever there’s a &lt;code&gt;keyup&lt;/code&gt; event, grab the element’s value, wrap it up
as a &lt;code&gt;TermChange&lt;/code&gt; &lt;code&gt;Action&lt;/code&gt;, and send it on its merry way.&lt;/p&gt;
&lt;h2 id=&quot;were-done&quot;&gt;We’re done&lt;/h2&gt;
&lt;p&gt;That’s it. A complete overview of a Geocoding module for an app
written in Elm. It feels like we covered a lot of pieces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Describing data&lt;/li&gt;
&lt;li&gt;Describing events&lt;/li&gt;
&lt;li&gt;Handling events&lt;/li&gt;
&lt;li&gt;AJAX-y side-effects&lt;/li&gt;
&lt;li&gt;Decoding JSON&lt;/li&gt;
&lt;li&gt;React-style rendering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that is a lot of pieces, but any app would need all of them
somewhere. The nice thing about this approach is that each piece is
discrete - you can think about it and write it in isolation, and then
glue them together later&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. You can also easily split the writing
of them, so that coders who are good with HTML can focus on the
rendering. I am muchly fond of this approach in general, and Elm’s
implementation of it specifically. Especially when it’s a hack day and
I need to move fast &lt;em&gt;without&lt;/em&gt; breaking things.&lt;/p&gt;
&lt;h2 id=&quot;fin&quot;&gt;Fin&lt;/h2&gt;
&lt;p&gt;The whole app is a little larger, and I’ll be writing up other
pieces. In the meantime, you can see the geocoding part in action by
&lt;a href=&quot;http://krisajenkins.github.io/beeline-demo/&quot;&gt;playing with the finished hackday app here&lt;/a&gt; and then &lt;a href=&quot;https://github.com/krisajenkins/beeline-demo&quot;&gt;read the source code&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;And they’re not paying me to say that. Well, actually, this app won a prize at the hackday, and ArcGIS were the sponsors, so maybe that does count as payment. :-D &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Thank you &lt;a href=&quot;https://twitter.com/rtfeldman&quot;&gt;Richard Feldman&lt;/a&gt; for that analogy. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Clojurians might find it interesting that this is very much like a &lt;code&gt;core.async&lt;/code&gt; channel, except it’s one-way. You can only write to an &lt;code&gt;Address&lt;/code&gt;, and it has a counterpart on the other side that can only be read from. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;It’s an approach that can work in many languages, but Elm makes the distinctions really clear. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Things I Love About Languages I Hate</title><link>https://blog.jenkster.com/2015/09/things-i-love-about-languages-i-hate.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/09/things-i-love-about-languages-i-hate.html</guid><pubDate>Fri, 25 Sep 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m worried I’ve seemed a bit grumpy about tech lately. So, in an
attempt to find silver linings and stream some positivity from my
corner of the technosphere&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, here are some things I love about
the things I hate:&lt;/p&gt;
&lt;h2 id=&quot;php&quot;&gt;PHP&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It has all the best content-management systems. God only knows why, but it does.&lt;/li&gt;
&lt;li&gt;It gets fast results for beginners, and you can’t underestimate the value of that.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bash&quot;&gt;Bash&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you just typed it at the command line, you’re 80% of the way to automating it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;javascript&quot;&gt;JavaScript&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It’s the only programming language my mother has installed. And my
grandmother. And, basically, everyone.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;plsql-and-variants&quot;&gt;PL/SQL (and variants)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It has, hands down, the best SQL integration of any language. That’s
the only thing it’s got, but it’s got that. If your job just involves
manipulating database rows, it’ll be written before your package
manager has finished downloading an internet’s worth of ORM
dependencies. And if your program processes a million database
rows, a PL/SQL can finish the job before your ORM has finished
deserialising the first 10,000.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;scala&quot;&gt;Scala&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Along with a few other, better languages, it’s a bit of a magnet for smart people right now.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;mean&quot;&gt;MEAN&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Mongo, Express, Angular &amp;amp; Node. It’s a really good acronym. I mean,
really good. It’s memorable and sounds cool &amp;amp; edgy.&lt;/li&gt;
&lt;/ul&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;How can you have a corner of a sphere? &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Timing Code in ClojureScript</title><link>https://blog.jenkster.com/2015/09/timing-code-in-clojurescript.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/09/timing-code-in-clojurescript.html</guid><pubDate>Fri, 25 Sep 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here’s a handy little ClojureScript macro that helps you time how long
code blocks take. It’s exactly like &lt;code&gt;(clojure.core/time)&lt;/code&gt;, in that it
takes a code block and tells you how long it took to execute, but
specially for ClojureScript it piggy-backs on the JavaScript &lt;code&gt;console&lt;/code&gt;
API, for pretty output in the inspector pane. You’d use it like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;console-time&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Rendering Big Thing&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;render-to-dom&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lots-of-data))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the browser’s inspector console will print out &lt;code&gt;Rendering Big Thing: 10070.868ms&lt;/code&gt; when it’s done.&lt;/p&gt;
&lt;p&gt;How does it work? Well, it’s really just wrapping a code block in two
&lt;code&gt;console&lt;/code&gt; API calls, &lt;code&gt;.time(&amp;lt;label&amp;gt;)&lt;/code&gt; and &lt;code&gt;.timeEnd(&amp;lt;label&amp;gt;)&lt;/code&gt;. We could almost say:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; console-time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [label &amp;amp; body]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  `(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.time&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; js/console ~label)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     ~@body&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.timeEnd&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; js/console ~label)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…splicing the body between those calls. But that would have a flaw:
instead of returning the body’s result value, we’re returning the
result of &lt;code&gt;console.timeEnd&lt;/code&gt;, which is always &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So we take a second pass:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; console-time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [label &amp;amp; body]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  `(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.time&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; js/console ~label)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     ~@body&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.timeEnd&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; js/console ~label)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     ~@body))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s pretty obvious that’s wrong too - right return value, but it’s
executing the body twice. That’s bad for performance, and outright
broken if &lt;code&gt;body&lt;/code&gt; contains side-effects&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;There’s nothing for it - we’re going to have to run the block once,
capture its return value, and return that captured result later.&lt;/p&gt;
&lt;p&gt;To capture it, we’ll have to create a temporary local var, with a
guaranteed-unique name. We can do that by appending a hash symbol, as
&lt;code&gt;result#&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that, the final code should make sense:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; console-time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [label &amp;amp; body]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  `(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.time&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; js/console ~label)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [result# (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ~@body)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.timeEnd&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; js/console ~label)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       result#)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Remember if you’re using this forreals, all ClojureScript macros must
go in a Clojure file, and be imported with &lt;code&gt;(refer-macros ...)&lt;/code&gt;.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Don’t worry, I know &lt;em&gt;you&lt;/em&gt; would never write code with side-effects. We’re worrying about &lt;em&gt;them&lt;/em&gt;. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Dude, Do You Even Fizzbuzz?</title><link>https://blog.jenkster.com/2015/09/dude-do-you-even-fizzbuzz.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/09/dude-do-you-even-fizzbuzz.html</guid><pubDate>Sat, 12 Sep 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ah, fizzbuzz, that venerable challenge of our industry. I’ve lost
count of the number of times I’ve been asked to fizzbuzz in an
interview. Seriously, I’d like to get a blindfold with “fizzbuzz”
embroidered on it, so if I’m sent to the whiteboard I can cover my
eyes and see if I’m yet able to Pin the Tail on the Fizzbuzz Donkey.&lt;/p&gt;
&lt;p&gt;Some people dislike it. Some refuse to do it at interview. Not
me. I’ve been on both sides of the interview table, and I’ve seen
glistening CVs turn into candidates that can barely find the right
side of the keyboard. So I’m fine with starting an interview with an
idiot filter. We’ll soon be on to talking about something more
interesting.&lt;/p&gt;
&lt;p&gt;But why am I writing about fizzbuzz? More importantly, why am I on
holidaycation, sitting at a free bar, and writing about fizzbuzz?
Because Someone Is Wrong On The Internet.&lt;/p&gt;
&lt;p&gt;I saw a blog post today on the “right way” to TDD fizzbuzz in an
interview, and it’s got my goat.&lt;/p&gt;
&lt;p&gt;I have mixed feelings about the value of TDD. I won’t get into the
gory details, because that’s worth an essay in itself, but the
particular aspect on my mind is that TDD has a tendency to lead you
into &lt;em&gt;spec blindness&lt;/em&gt;. That condition that every junior developer has
to learn about, where you think that correctly fulfilling the spec
leads to correct code (and a pat on the head). It does not. You
graduate from junior developer when you start seeing the need behind
the presenting problem&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. And with fizzbuzz, the spec is
deeply misleading.&lt;/p&gt;
&lt;p&gt;The spec goes something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Given an integer n, print the integers from 0 to n.&lt;/li&gt;
&lt;li&gt;Every time you reach a number wholly divisible by 3, print ‘fizz’ instead.&lt;/li&gt;
&lt;li&gt;Every time you reach a number wholly divisible by 5, print ‘buzz’ instead.&lt;/li&gt;
&lt;li&gt;Every time you reach a number wholly divisible by 3 &lt;em&gt;and&lt;/em&gt; 5, print ‘fizzbuzz’ instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, Mr Wrong On The Internet advocates starting with this test case:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;assertEquals&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;fizz&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fizzbuzz&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)[&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yes, this hits the spec. But it’s testing too many things, and has
tests of trivia mixed in with testing useful code. But the big problem
is, if you start with “test the spec” as your guide then it’s
encouraging you to write the wrong code. It’s the programming
equivalent of treating the symptoms instead of going for the root
cause.&lt;/p&gt;
&lt;p&gt;Instead of string-munging through the symptoms, let’s step back and do
some quick analysis&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; on this problem. Fizzbuzz has few parts, and
almost all of them are crashingly dull:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Print stuff as a string&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yawn.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Generate a sequence from 0 to n.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yawn. &lt;code&gt;(range n)&lt;/code&gt;, or your language’s equivalent. Next.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Apply a transformation to a sequence.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Dull programming, but it does open the opportunity to pontificate
about functional programming. I could probably even get the word
‘Functor’ in there, and that always gets the day moving. Still, dull
programming.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Conditionally transform an integer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There’s the nugget. This is the /only/ interesting part of the
challenge. Fizzbuzz can be written as:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; n)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; f)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…where &lt;code&gt;f&lt;/code&gt; is the /only/ thing doing anything novel. Any coding you
do outside of defining &lt;code&gt;f&lt;/code&gt; is merely gluing the algorithm into the
core libraries. And so I put it to you, any testing you do outside of
testing &lt;code&gt;f&lt;/code&gt; is an integration test, and a crashingly dull one at
that. You might as well include writing tests for &lt;code&gt;.toString()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if you ever ask me to write fizzbuzz in an interview, I’ll start by
writing a function of type &lt;code&gt;Int -&amp;gt; String&lt;/code&gt;. Actually I’ll probably do
it in Clojure, because I think it comes out neatest:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [n]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;mod&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;mod&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _] &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fizz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:buzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    :else&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; n))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or maybe I’ll go typecrazy with Haskell:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Natural&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Int&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Fizz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Buzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; FizzBuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  deriving&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Show&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#50FA7B&quot;&gt;fizzbuzz&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;fizzbuzz n &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  case&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (mod n &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,mod n &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; FizzBuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,_) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Fizz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (_,&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Buzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    _ &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; Natural&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; n&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s sweet. It changes the type and still keeps the untransformed
integers available.&lt;/p&gt;
&lt;p&gt;Someone will say I’m doing TDD wrong. So be it. I’m a heretic. I’m
saying if TDD is, “translating the spec-as-given into a test and then
writing passing code,” then TDD is wrong&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. However I solve fizzbuzz,
you won’t see me start with string-slicing tests&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;And you graduate to senior developer when you learn to stop always trying to see the bigger picture, and remember that you’ve also just gotta ship. Balancing the bigger picture with the smaller one never ends. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Henderson’s Law states that all problems can be solved with one of two approaches: 1) Think, and 2) For chrissakes, THINK! &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Someone will say that that isn’t TDD either. Bravo! Please continue to say it. Please say it louder, so as to drown out the mainline rhetoric. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;Besides, for fizzbuzz you want property-based testing, not example-based. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Responsive YouTube Videos With Elm</title><link>https://blog.jenkster.com/2015/09/responsive-youtube-videos-with-elm.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/09/responsive-youtube-videos-with-elm.html</guid><pubDate>Sun, 06 Sep 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently &lt;a href=&quot;http://devpost.com/software/beeline-demo/&quot;&gt;wrote an navigation app for a hack day&lt;/a&gt;, and since it’s
written in Elm, and there aren’t enough blog posts about Elm, I
thought I’d break down some of the pieces. Let’s warm up with a
simple, but exceptionally useful one: Embedding a responsive video.&lt;/p&gt;
&lt;p&gt;This is so easy it’s almost cheating. Most of the hard work is
offloaded to &lt;a href=&quot;http://getbootstrap.com/components/#media&quot;&gt;Bootstrap 3&lt;/a&gt;. But since it’s so useful it’s worth spelling
out. All we need is a function that takes a YouTube URL, and returns
some HTML. That translates to this type signature:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;youtube&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; Html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we need to know how to generate HTML in Elm. It’s pretty
easy. Almost every HTML function takes a list of attributes, followed
by a list of children. So a Bootstrap alert messsage might be:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;alert&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    div [ class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;alert alert-danger&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        [ text &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Ohnoes!&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…or with a title:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;alert&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    div [ class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;alert alert-danger&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        [ h1 []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            [ text &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Error!&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        , text &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Ohnoes!&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(You can see there in the &lt;code&gt;h1&lt;/code&gt; tag that you &lt;em&gt;must&lt;/em&gt; specify the list of
attributes, even if it’s empty.)&lt;/p&gt;
&lt;p&gt;With that, the code for our &lt;code&gt;youtube&lt;/code&gt; function is an easy
translation of the Bootstrap docs:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elm&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elm&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;youtube&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; url &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    div [ class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;embed-responsive embed-responsive-16by9&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        [ iframe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            [ class &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;embed-responsive-item&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            , src url&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s all there is to it.&lt;/p&gt;
&lt;p&gt;(For the curious, &lt;a href=&quot;http://package.elm-lang.org/packages/krisajenkins/elm-exts/8.4.0/Exts-Html-Bootstrap#video&quot;&gt;I’ve published a slightly fancier version&lt;/a&gt; as a library.)&lt;/p&gt;
</content:encoded></item><item><title>When Should You Bother With A Reader Monad?</title><link>https://blog.jenkster.com/2015/08/when-should-you-bother-with-a-reader-monad.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/08/when-should-you-bother-with-a-reader-monad.html</guid><pubDate>Thu, 06 Aug 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;I have been thinking about Reader monads, and the bothering-with
thereof. Here’s this morning’s stream of consciousness…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Thought of the day - what’s the difference between using a function
&lt;code&gt;foo :: Config -&amp;gt; SomeResult&lt;/code&gt; and using the monad &lt;code&gt;foo :: Reader Config SomeResult&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Answer: Technically none. &lt;code&gt;data Reader r a = Reader { runReader :: r -&amp;gt; a }&lt;/code&gt;
is really an equation saying they’re exactly equivalent: &lt;code&gt;Reader r a&lt;/code&gt; equals &lt;code&gt;r -&amp;gt; a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So what’s the point of the Reader monad? Why (or rather, when) should
you bother with a Reader monad instead of a straight argument?&lt;/p&gt;
&lt;p&gt;Answer: composition. The &lt;code&gt;Reader&lt;/code&gt; version composes
(maps/sequences/etc.) trivially, to produce a single function that’s
just waiting for its config. The vanilla version requires more
plumbing (&amp;amp; thought) to compose.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Partly that’s offset in Clojure - we don’t just use functional
composition, we can use syntactic composition too (because macros).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But that’s my conclusion of a night in the hammock. The Reader monad
is a transformational trick to enable easier functional
composition. And so, the “should I use it?” question follows as, “am I
doing a lot of &lt;code&gt;config&lt;/code&gt; plumbing to sequence these function calls?”&lt;/p&gt;
</content:encoded></item><item><title>Extending Esqueleto for Type-Safe Postgresql Queries</title><link>https://blog.jenkster.com/2015/07/extending-esqueleto-for-type-safe-postgresql-queries.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/07/extending-esqueleto-for-type-safe-postgresql-queries.html</guid><pubDate>Tue, 28 Jul 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s no great secret that &lt;a href=&quot;https://github.com/krisajenkins/yesql&quot;&gt;I’m not a huge fan of SQL DSLs&lt;/a&gt;. They tend to
be great for the simple stuff, but they break down very quickly
as soon as you try to do anything non-trivial. So it’s a bit odd
that I find myself picking up a Haskell one - &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto&quot;&gt;Esqueleto&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Why am I risking heartbreak? Well, because as long as I can stay
on the Persistent/Esqueleto path, I’ll get DB migrations for free,
and compile-time integrity checks that can cover my database,
webserver and frontend in one pass.&lt;/p&gt;
&lt;p&gt;That kind of compile-time checking - for almost-free - is not to be
sniffed at. If I change a datastructure, I know that the all the
server code, all the UI code and the complete database schema are in
sync. I don’t think I’ve ever worked on a project that’s achieved that
dream, so it’s worth a little perseverance.&lt;/p&gt;
&lt;p&gt;As predicted, Esqueleto broke down for me pretty quickly. But it got
back up off the floor quickly too, and that’s the point of this post:
Let’s see how we can get a typesafe database query that uses SQL
features the library authors didn’t consider…&lt;/p&gt;
&lt;p&gt;My use-case, I confess, is weird. But that’s sort of the point - this
is stuff the authors wouldn’t have foreseen. I am importing some data
from a shoddy source, and then cleaning it up later. So I already had
this SQL statement:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sql&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  UPDATE&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; product&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  SET&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; description&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; trim&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(chr(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;160&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; description&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  WHERE&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; description&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; trim&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(chr(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;160&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; description&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For some reason &lt;code&gt;$DATA_SUPPLIER&lt;/code&gt; is sticking weird characters around
the description, and we didn’t catch it on import. We want to update
any products that have the magic character &lt;code&gt;chr(160)&lt;/code&gt; stuck on them.&lt;/p&gt;
&lt;p&gt;Let’s see that update statement naively ported to Esqueleto:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;  tidyDescriptions&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; SqlPersistM&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  tidyDescriptions &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    update &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;product &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; do&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; set product [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;ProductDescription&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; =.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; trimDescription product]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   where_ ((product &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;^.&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ProductDescription&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;!=.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (trimDescription product))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    where&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; trimDescription product &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            (trim (chr (val &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;160&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                  (product &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;^.&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; ProductDescription&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The syntax is a little funky, but even if you don’t really read
Haskell you can probably see how it’s trying to say the same thing as
the SQL above.&lt;/p&gt;
&lt;p&gt;Unfortunately, Esqueleto has already broken down on us: &lt;code&gt;trim&lt;/code&gt; and
&lt;code&gt;chr&lt;/code&gt; are apparently too Postgres-specific, and aren’t supported.&lt;/p&gt;
&lt;p&gt;So what shall we do? Break out a horrible, string-guzzling &lt;code&gt;rawSql&lt;/code&gt;
function, losing type safety and opening up SQL Injection vectors? No!
We just teach Esqueleto about these functions. First &lt;code&gt;chr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chr&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;IsString&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; SqlExpr&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; SqlExpr&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;chr &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; unsafeSqlFunction &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;chr&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code basically reads as, “There’s a function called =chr= that
takes an integer and returns a string, both in a SQL-ish context. Trust
me. There really is.”&lt;/p&gt;
&lt;p&gt;And then:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;haskell&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;trim&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;IsString&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;     =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; SqlExpr&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; SqlExpr&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt; SqlExpr&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD;font-style:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;trim pattern target &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  unsafeSqlFunction &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;trim&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    (unsafeSqlBinOp &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; pattern target)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which reads as, “There’s a function called &lt;code&gt;trim&lt;/code&gt; that
takes two strings and has weird syntax, but if you call it this way
you’ll get a string back. Honest.”&lt;/p&gt;
&lt;p&gt;With that, our &lt;code&gt;update&lt;/code&gt; statement works. We don’t get type-safety
&lt;em&gt;within&lt;/em&gt; these functions - Haskell is just blindly taking our promise
that these types are correct - but I can live with that. This is code
we’ll write once and never change. The important thing is that every
&lt;em&gt;use&lt;/em&gt; of these new functions get the guarantees we’re looking for, and
they were pretty trivial to add.&lt;/p&gt;
&lt;p&gt;So an SQL DSL that doesn’t abandon you to DSHell. Cautiously, I
&lt;em&gt;think&lt;/em&gt; I could make friends here…&lt;/p&gt;
</content:encoded></item><item><title>Map, Reduce and the Fold-Twins</title><link>https://blog.jenkster.com/2015/07/map-reduce-and-the-fold-twins.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/07/map-reduce-and-the-fold-twins.html</guid><pubDate>Tue, 07 Jul 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;map&lt;/code&gt; &amp;amp; &lt;code&gt;reduce&lt;/code&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; are the bread &amp;amp; butter tools of functional
programming, but if you’re new to FP it’s easy to get muddled about
which to use when, so here’s my mental checklist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you have a sequence and you want a sequence, use &lt;code&gt;map&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you have a sequence and you want a single value, use &lt;code&gt;reduce&lt;/code&gt; (or&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fold&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;If you have a single value and you want a sequence, use &lt;code&gt;unfold&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s a simplification, but a good rule of thumb to get started
with. (The twist comes when you realise that the “single value” that
&lt;code&gt;reduce&lt;/code&gt; produces can itself be a new sequence.) But hopefully that
will serve as a simple signpost if you’re coming from a world of &lt;code&gt;for&lt;/code&gt;
loops and wondering how to break things down.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Or &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;fold&lt;/code&gt;/&lt;code&gt;foldl&lt;/code&gt;/&lt;code&gt;foldr&lt;/code&gt; , depending on your language. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>This Week In The Browser</title><link>https://blog.jenkster.com/2015/07/this-week-in-the-browser.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/07/this-week-in-the-browser.html</guid><pubDate>Wed, 01 Jul 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;ClojureScript has &lt;a href=&quot;https://asciinema.org/a/22767&quot;&gt;opened a window to no-JVM&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;Elm has &lt;a href=&quot;http://elm-lang.org/blog/compiler-errors-for-humans&quot;&gt;released a big improvement in its compiler errors&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;PureScript has &lt;a href=&quot;https://github.com/purescript/purescript/releases/tag/v0.7.0&quot;&gt;released an order of magnitude performance boost&lt;/a&gt; in its compiler times…&lt;/p&gt;
&lt;p&gt;And there is genuine hope of &lt;a href=&quot;https://github.com/commercialhaskell/stack/issues/337&quot;&gt;progress for practical GHCJS&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;I’m calling this a good week for the browser.&lt;/p&gt;
</content:encoded></item><item><title>JavaScript - The Collection of Parts</title><link>https://blog.jenkster.com/2015/06/javascript-the-collection-of-parts.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/06/javascript-the-collection-of-parts.html</guid><pubDate>Wed, 17 Jun 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;JavaScript is awful.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;It’s got Good Parts!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yes, but it’s also got Bad Parts. Lots of them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We won’t use those parts.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll be disciplined.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Seriously, how?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll be really disciplined.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hmm. What about the pitfalls you don’t all know about?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Okay, we’ll use a linter.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That would shield you from the Worst Parts.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use ES2015.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That would shield you from the Next-to-Worst Parts.&lt;/p&gt;
&lt;p&gt;What about the poor async support?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use Promises.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What about the broken data-modeling?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use ImmutableJS.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What about the broken data-processing?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use Underscore.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What about the broken data-flow?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use RxJS.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What about the broken data-consistency?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use TypeScript.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What about the broken rendering?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’ll use React.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Why don’t you just start with a well-designed language?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Oh we couldn’t do that - there’d be too much to learn!&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>A Brief And Partial Review Of Haskell In The Browser</title><link>https://blog.jenkster.com/2015/02/a-brief-and-partial-review-of-haskell-in-the-browser.html</link><guid isPermaLink="true">https://blog.jenkster.com/2015/02/a-brief-and-partial-review-of-haskell-in-the-browser.html</guid><pubDate>Tue, 03 Feb 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ah, the browser. Like iOS, it’s a place of pleasure and pain. Love the
audience it reaches; hate the default language. So I have a keen interest in
the rise of “Compiles to JavaScript” languages. ClojureScript is my
current weapon of choice, and I’m very happy with it. But I’ve also
spent a chunk of time researching Haskell-like options for the
browser, and I thought I’d write up my experiences.&lt;/p&gt;
&lt;p&gt;Before we begin, for context, here is:&lt;/p&gt;
&lt;h2 id=&quot;what-im-looking-for-in-a-browser-language&quot;&gt;What I’m Looking For In A Browser Language&lt;/h2&gt;
&lt;h3 id=&quot;sane-language-design&quot;&gt;Sane language design&lt;/h3&gt;
&lt;p&gt;That rules out JavaScript, CoffeeScript, TypeScript, ScalaJS and several others.&lt;/p&gt;
&lt;h3 id=&quot;separation-of-logic--rendering&quot;&gt;Separation of logic &amp;amp; rendering&lt;/h3&gt;
&lt;p&gt;If your onClick handler references business-logic functions directly,
something is wrong.&lt;/p&gt;
&lt;h3 id=&quot;no-manual-dom-manipulation&quot;&gt;No manual DOM manipulation&lt;/h3&gt;
&lt;p&gt;Are you still doing that? Stop it. Unless you enjoy manual memory
management too. (In which case good luck to you, my fine retronaught.)&lt;/p&gt;
&lt;h3 id=&quot;no-callbacks&quot;&gt;No callbacks&lt;/h3&gt;
&lt;p&gt;Our brains are happiest with a single line of control flow. Yes you
can get comfortable with callback-passing, but it never sits as easily
as not having to. And like DOM manipulation, you don’t have to
anymore. It’s a job for the language, not for you. Save your brain.&lt;/p&gt;
&lt;h2 id=&quot;the-players&quot;&gt;The Players&lt;/h2&gt;
&lt;h3 id=&quot;ghcjs&quot;&gt;GHCJS&lt;/h3&gt;
&lt;p&gt;GHCJS reuses the GHC compiler we all know &amp;amp; love, but modifies it to
emit JavaScript. The result is extremely impressive. You really do get
a full Haskell experience. The language features are the same, the
compiler messages the same, even most stuff on Hackage just
works. It’s good.&lt;/p&gt;
&lt;p&gt;I’ve heard people complain about the size of the JS files it
produces. Apparently in the early days it was particularly bad, but to
me, now, it seems perfectly acceptable. Once a production webapp will
minify &amp;amp; gzip to less than the size of an animated cat gif, it’s time
to stop yapping about file sizes.&lt;/p&gt;
&lt;p&gt;There were three downsides with GHCJS for me. The first is, how should
you structure a full client-side app? &lt;a href=&quot;https://github.com/krisajenkins/bellringer&quot;&gt;I did some work on this with Ben Ford&lt;/a&gt;, and then he &lt;a href=&quot;https://github.com/boothead/ohm&quot;&gt;took it much further&lt;/a&gt;, but it’s still very much an
area of research. I couldn’t say to anyone, “This is the way to build
it; you’ll need these pieces.”&lt;/p&gt;
&lt;p&gt;The second problem is that GHCi isn’t supported yet. Without that, I
found incremental build times to be just a bit too long, even for a
small app.&lt;/p&gt;
&lt;p&gt;And the third problem, and for me the nail in the coffin, is it’s a
real pain to install. If you thought cabal hell was hell, I can tell
you there’s another layer of problems lying in wait. Honestly, I
couldn’t even say to anyone, “You should try GHCJS.” Getting started is
asking too much.&lt;/p&gt;
&lt;p&gt;All these problems will be addressed, and quickly I expect. Simply
because of the quality of compiler, GHCJS is the one to watch. But
I’ve put it aside for now.&lt;/p&gt;
&lt;h3 id=&quot;haste&quot;&gt;Haste&lt;/h3&gt;
&lt;p&gt;If not GHCJS, how about another, “Let’s make regular GHC emit
JavaScript!” approach? That’s what Haste does.&lt;/p&gt;
&lt;p&gt;I liked Haste initially, until I got to that absolutely necessary
evil, JavaScript interop, and everything fell apart. I recall I wanted
to share a simple list of integers between Haste and JavaScript, and I
couldn’t do it. The official position seems to be, “Yes, it ought to
be easy. If you have a patch I’ll merge it.”&lt;/p&gt;
&lt;p&gt;If Haste needs serious expertise to pass &lt;code&gt;[1, 2, 3]&lt;/code&gt;, then it’s not for me.&lt;/p&gt;
&lt;h3 id=&quot;purescript&quot;&gt;PureScript&lt;/h3&gt;
&lt;p&gt;PureScript moves us away from GHC and into languages that are
styled-after Haskell. PureScript seems to be winning a popular vote
(in this ultra-niche), and I can see why. The language has the
headline features from Haskell, interop is good, it all works, and the
documentation is excellent.&lt;/p&gt;
&lt;p&gt;There are a few downsides for me that eventually stacked up too
high. Tooling’s a bit of a pain. (You’ll need Node. And Grunt. And
Bower. Wait, are we actually building a JavaScript project?)&lt;/p&gt;
&lt;p&gt;The compiler errors are…disappointing. Haskell development leans
heavily on fast, high-quality feedback from the type system. If you
squint, the GHC compiler is almost a REPL. From what I gather, GHC has
taken a vast amount of engineering effort to get to where it is, so
you can’t blame PureScript for lagging behind. But lag it does, and
when PureScript spits out a type error, I feel very much alone.&lt;/p&gt;
&lt;p&gt;And finally, the “how do we structure/how do we render?” question felt
unanswered. There is a virtual DOM library, but it was scrappy. I
didn’t have an Om-quality experience using it. I’m sure it will
get better, but like GHCJS it feels like an untrodden path.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bonus Tip: If you’re playing with PureScript, Take a look at &lt;a href=&quot;https://github.com/bodil/pulp&quot;&gt;Bodil Stokke’s Pulp&lt;/a&gt; for your building needs. That worked well for me.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;elm&quot;&gt;Elm&lt;/h3&gt;
&lt;p&gt;Elm is nice. Very nice. The language is good. Control flow is
sane. The documentation is expansive (though more scattered about than
PureScript). Incremental compilation times are pleasing. The compiler
feedback is good. (No GHC, but better than PureScript.) Interop is so
easy it makes you wonder why interop is hard.&lt;/p&gt;
&lt;p&gt;The tooling’s excellent, even before you get into the fancy stuff like
the time-travelling debugger. You can just write some code, compile it
in seconds, get a single page you can upload straight to S3, and your
website’s running. And the path from that to a proper minified,
production app is smooth enough.&lt;/p&gt;
&lt;p&gt;I’ve heard people say Elm is great for game-like things, but little
attention has been given to regular HTML apps. That’s not true. The
&lt;a href=&quot;https://github.com/evancz/elm-html&quot;&gt;elm-html&lt;/a&gt; library is, give or take, a perfect substitute for Om/React.&lt;/p&gt;
&lt;p&gt;And the FRP approach may prove a bit of a learning curve for some, but
I found it very natural. There’s a certain way that I’ve been
structuring my ClojureScript apps, and Elm feels like it’s taking the
same route, but has baked it into the language. I heartily approve.&lt;/p&gt;
&lt;p&gt;On the downside, I do really wish it had typeclasses. And not even for
shiny things like putting my monoids in the category of
endofunctors. Just for simple stuff. Having to qualify &lt;code&gt;List.map&lt;/code&gt;,
&lt;code&gt;Signal.map&lt;/code&gt; and &lt;code&gt;Set.map&lt;/code&gt; gets old very quickly. And Json decoding
would be much simpler if it supported return-type polymorphism.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As you can probably guess, for now I’ve settled on Elm. I’m building
an MVP for a startup of my own at the moment, and the front end is
Elm. I’ll let you know how it goes.&lt;/p&gt;
&lt;p&gt;Oh, and I’ll be keeping my eye on GHCJS…&lt;/p&gt;
&lt;h2 id=&quot;coda&quot;&gt;Coda&lt;/h2&gt;
&lt;p&gt;Last week I went to an Elm night at Twitter HQ and Tom Ashworth was
speaking. I asked him if he thought Elm was ready for production. He
said no. I wish I’d also asked if he thought JavaScript was ready for
production… :-)&lt;/p&gt;
</content:encoded></item><item><title>An Elegant Little core.async Solution</title><link>https://blog.jenkster.com/2014/02/an-elegant-little-coreasync-solution.html</link><guid isPermaLink="true">https://blog.jenkster.com/2014/02/an-elegant-little-coreasync-solution.html</guid><pubDate>Thu, 20 Feb 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday I had a problem that &lt;code&gt;core.async&lt;/code&gt; provides an incredibly neat
solution to. Tim Baldridge was kind enough to sanity check it for me,
so I thought I’d write it up.&lt;/p&gt;
&lt;p&gt;Imagine you want to process a message at a maximum rate of one per
second. In another language you’d probably say something like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;python&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; true:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    start_time &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; date()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    process_message(queue)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    end_time &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; date()&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:#F8F8F2&quot;&gt;    elapsed_time &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; end_time.subtract(start_time)&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:#FF79C6&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; elapsed_time &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        sleep(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; elapsed_time)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not hard to write, of course, but kinda clumsy. Here’s the &lt;code&gt;core.async&lt;/code&gt;
version:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [t (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;timeout&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;process-message&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; queue)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;&amp;lt;!!&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; t)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In English, pick up a ticket that lasts for 1000 milliseconds; process
a message; wait until the ticket expires. If processing the message
took more than 1000ms, the ticket returns immediately, otherwise it
blocks for the remaining time.&lt;/p&gt;
&lt;p&gt;Simple &lt;em&gt;and&lt;/em&gt; easy. A really neat solution.&lt;/p&gt;
</content:encoded></item><item><title>Backwards Compatibility Testing For Your Clojure Project</title><link>https://blog.jenkster.com/2014/02/backwards-compatibility-testing-your-clojure-project.html</link><guid isPermaLink="true">https://blog.jenkster.com/2014/02/backwards-compatibility-testing-your-clojure-project.html</guid><pubDate>Thu, 20 Feb 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Leiningen makes it really easy to test your project against multiple
versions of Clojure. Really staggeringly easy. Like, “I don’t know a
single other language where this is so seamless,” easy. It’s a little
trick I picked up from &lt;a href=&quot;http://clojure.github.io/java.jdbc/&quot;&gt;clojure.java.jdbc&lt;/a&gt;, and I make good use of it in
&lt;a href=&quot;https://github.com/krisajenkins/yesql&quot;&gt;Yesql&lt;/a&gt;. Here’s how it goes:&lt;/p&gt;
&lt;p&gt;Since version 2, Leiningen lets you specify multiple profiles, with
their own dependency lists. What’s interesting is that Clojure itself
can be one of those dependencies, so we can meaningfully add this to
&lt;code&gt;project.clj&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;:profiles {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:1.4&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:dependencies&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [[org.clojure/clojure &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;1.4.0&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;           :1.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:dependencies&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [[org.clojure/clojure &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;1.5.1&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;           :1.6&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:dependencies&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [[org.clojure/clojure &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;1.6.0-beta1&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]]}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now calling &lt;code&gt;lein with-profile +1.4 test&lt;/code&gt; means “run &lt;code&gt;lein test&lt;/code&gt; under
default profile &lt;code&gt;dev&lt;/code&gt;, &lt;em&gt;plus&lt;/em&gt; merge in the &lt;code&gt;1.4&lt;/code&gt; profile”. Upshot: the
code runs as normal, but under Clojure 1.4.&lt;/p&gt;
&lt;p&gt;Now just add this alias:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;:aliases {&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;test-all&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;with-profile&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;+1.4:+1.5:+1.6&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…and &lt;code&gt;lein test-all&lt;/code&gt; will run the test suite three times, under each
of Clojure 1.4, 1.5 and 1.6, automatically.&lt;/p&gt;
&lt;p&gt;You can use that same trick for any dependency variations you like -
so you could check against different versions of your database driver,
for instance - but it’s this 4-line use case that really made my jaw
drop.&lt;/p&gt;
</content:encoded></item><item><title>Using Joda Time as your Clojure inst Class</title><link>https://blog.jenkster.com/2014/02/using-joda-time-as-your-clojure-inst-class.html</link><guid isPermaLink="true">https://blog.jenkster.com/2014/02/using-joda-time-as-your-clojure-inst-class.html</guid><pubDate>Sat, 08 Feb 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In Clojure, the reader-literal &lt;code&gt;#inst&lt;/code&gt; reads &amp;amp; writes
java.util.Dates. For instance:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; #inst &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;2014-02-06T00:00:00Z&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;;=&amp;gt; java.util.Date&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;pr-str&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;java.util.Date.&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;;=&amp;gt; #inst &quot;2014-02-08T15:54:49.949-00:00&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But it’s possible to replace that behaviour to read and write Joda
time instances. Here’s how:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;DISCLAIMER&lt;/em&gt; This may be a terrible idea. In fact it probably is. Go
away, unless you enjoy standing in the middle of a thunderstorm
cackling, “It’s Alive! It’s Alive!”&lt;/p&gt;
&lt;p&gt;Still with me? That’s the spirit!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;First&lt;/em&gt; you’ll need &lt;code&gt;clj-time&lt;/code&gt;. Add this to your &lt;code&gt;project.clj&lt;/code&gt;’s &lt;code&gt;:dependencies&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;[clj-time &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;0.6.0&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Second&lt;/em&gt; To get Clojure to read #insts as &lt;code&gt;org.joda.time.DateTime&lt;/code&gt; classes, add this to &lt;code&gt;src/data_readers.clj&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;{inst clj-time.format/parse}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That just switches out the function that turns strings into date
objects. Restart your REPL session to pick that up.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Third&lt;/em&gt; You’ll need to implement a printing method, so that the classes
are written as &lt;code&gt;#inst&lt;/code&gt;-tagged strings:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defmethod&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; print-dup org.joda.time.DateTime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [o writer]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;.write&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; writer (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;#inst &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; o)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure that code’s been imported into any namespace where you want
this to work. Now you can say:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:start&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; #inst &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;2014-02-06T00:00:00.000-00:00&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;   :end&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; #inst &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;2014-02-06T02:00:00.000-00:00&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And get a map whose values are Joda &lt;code&gt;DateTime&lt;/code&gt; objects.&lt;/p&gt;
&lt;p&gt;As I say, this is probably a bad idea. It’ll unexpectedly break things
for people. But it’s a fun hack anyway, so I thought I’d record it.&lt;/p&gt;
</content:encoded></item><item><title>Our Total Quality Approach to Software</title><link>https://blog.jenkster.com/2014/01/our-total-quality-approach.html</link><guid isPermaLink="true">https://blog.jenkster.com/2014/01/our-total-quality-approach.html</guid><pubDate>Sat, 25 Jan 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here at CueCorp Ltd. we have a total approach to software Quality,
experimenting with every possible angle to maximize shareholder value.&lt;/p&gt;
&lt;p&gt;Our &lt;em&gt;Quality Insurance&lt;/em&gt; department collects a regular monthly premium
from our developers. In the event that bad code gets released to
production, the devs put in a claim and get sent a cheque to cover the
cost of fixing it. Premiums are climbing, but we have high hopes for
this innovative, market-driven approach to Quality.&lt;/p&gt;
&lt;p&gt;Our &lt;em&gt;Quality Assurance&lt;/em&gt; department wanders around the office daily,
talking to devs, managers and all other staff, confidently assuring
them that the software will work. We’re not 100% sure of the value of
this, but we checked the dictionary and it confidently assured us that
that’s what ‘assurance’ means.&lt;/p&gt;
&lt;p&gt;Our &lt;em&gt;Quality Ensurance&lt;/em&gt; department is our most successful arm. Though
their remit is wide, they take every angle and every opportunity to
ensure the quality of our software. By writing test suites,
by training our devs, by explaining the value of refactoring to our
management team, by working with our architects to choose simpler and
more reliable tools - there is no approach they won’t try to ensure
that they ensure what they’re supposed to ensure.&lt;/p&gt;
&lt;p&gt;Obviously, Quality is our highest priority, and our structure is an
ongoing experiment. If you care more about software Quality than
labels, rest assured (ensured? insured?) there’s a place for you here
at CueCorp!&lt;/p&gt;
</content:encoded></item><item><title>Book Review - Clojure for Domain Specific Languages</title><link>https://blog.jenkster.com/2014/01/book-review-clojure-for-domain-specific-languages.html</link><guid isPermaLink="true">https://blog.jenkster.com/2014/01/book-review-clojure-for-domain-specific-languages.html</guid><pubDate>Sat, 18 Jan 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What a great title, eh? Clojure’s a fantastic language for writing
DSLs, and yet it’s a hard topic get into. A good book on the subject
is just what the Clojure ecosystem needs.&lt;/p&gt;
&lt;p&gt;Sadly, this isn’t that book.&lt;/p&gt;
&lt;p&gt;The biggest problem is that there’s hardly any content about writing
DSLs. This is a ~240 page book, and about 200 of that is just “Intro
to Clojure” stuff. That would be fine, but there are much better
introductory books out there.&lt;/p&gt;
&lt;p&gt;Filler aside, that leaves maybe 40 pages that are actually about writing
DSLs. Sadly it’s the weakest stuff in the book. It consists of two
examples of using Clojure to wrap existing Java libraries. One’s a
Twitter client, the other’s a wrapper around Java’s Date &amp;amp; Calendar
classes. And there’s no way around saying this - both are badly written.&lt;/p&gt;
&lt;p&gt;It would be a terrible shame if any beginner in Clojure read this
stuff and thought it was a good way to proceed. What should be a
simple function to read a config file into a map is presented in an
overwrought &amp;amp; brittle fashion. Macros are used frequently but never
appropriately. Clojure code drops down into Java interop for no good
reason at all. And the author seems to have an obsession with
dynamically-binding variables, regardless of whether it’s appropriate.
I strongly suspect this betrays a lack of understanding about what
they’re for. Either way, the Twitter DSL is going to break as soon as
you do anything interesting with it, like delay the results. (Stuart
Sierra has &lt;a href=&quot;http://stuartsierra.com/2013/03/29/perils-of-dynamic-scope&quot;&gt;a great post about it&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;So is there anything here to like? Yes, the author is quite lucid. His
technical writing reads easily. I hope he writes a book on another
topic one day - but he’ll need to be far better versed in the
material.&lt;/p&gt;
&lt;p&gt;In the meantime, if you want an intro to Clojure book, check out the
superb &lt;a href=&quot;http://www.amazon.com/gp/product/1935182641/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1935182641&amp;amp;linkCode=as2&amp;amp;tag=blogjenksterc-20&quot;&gt;Joy of Clojure&lt;/a&gt;. And if you’re a seasoned Clojure programmer
looking for a good book on DSL writing…well…so am I. In the
meantime, &lt;a href=&quot;http://pragprog.com/magazines/2011-07/growing-a-dsl-with-clojure&quot;&gt;here’s a good article&lt;/a&gt; on one application of the technique…&lt;/p&gt;
</content:encoded></item><item><title>Tech I Want To Build/Learn In 2014</title><link>https://blog.jenkster.com/2013/12/tech-2014.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/12/tech-2014.html</guid><pubDate>Tue, 31 Dec 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last day of 2013, and it’s time to look ahead to the year to
come. Here are my tech aims for 2014:&lt;/p&gt;
&lt;h2 id=&quot;learn-haskell&quot;&gt;Learn Haskell&lt;/h2&gt;
&lt;p&gt;I decided last year I wasn’t going to learn any new
languages&lt;sup&gt;&lt;a href=&quot;#user-content-fn-scala&quot; id=&quot;user-content-fnref-scala&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Instead I was going to double down &amp;amp; get &lt;em&gt;really
tasty&lt;/em&gt; at Clojure. There’s still plenty of deliciousness left in that
journey, but I think I’ve done well enough to pick up a little
something new.&lt;/p&gt;
&lt;p&gt;But what new thing should I choose? Well, probably the best advice I
heard all year was from &lt;a href=&quot;https://twitter.com/sanityinc&quot;&gt;Steve Purcell&lt;/a&gt;, which I’ll paraphrase as,
“Figure out what the smartest, nicest people you can find are
learning, and learn that.” I look around and see Clojure &amp;amp; Haskell
fitting that description, so it feels like the time is coming.&lt;/p&gt;
&lt;p&gt;(Actually, Haskell isn’t new to me. It’s just my Haskell skills are so
crusty as to earn a seat in the House of Lords. A 15-year hiatus, by my
calculations.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chances of it happening&lt;/em&gt;: Strong. I love a new language. Would be nice
if I had a commercial reason to motivate it though.&lt;/p&gt;
&lt;h2 id=&quot;write-a-good-database-reporting-system&quot;&gt;Write A Good Database Reporting System&lt;/h2&gt;
&lt;p&gt;Reports servers, universally, suck. In roughly-chronological order,
I’ve used Oracle Reports, BIRT, Oracle Apex, JasperReports &amp;amp; Crystal
Reports, and not one of them has shed a glimmer of hope. They’re
tolerable, but they’re not good.&lt;/p&gt;
&lt;p&gt;Here’s a test you can apply to see if your report-server sucks: Which
is easier? Adding a pink circle to the top-left corner of a report, or
adding a new column to it and pushing it live?&lt;/p&gt;
&lt;p&gt;The fact that it’s easier to find the ellipse button than the deploy
button is proof that something is tragically wrong.&lt;/p&gt;
&lt;p&gt;I know why they all suck. I know exactly why. It’s because they’re
designed on a lie. The lie is, “Use our tool and you can just drag &amp;amp;
drop reports together. You’ll never need to learn SQL and you’ll never
need to ask IT again.”&lt;/p&gt;
&lt;p&gt;BS. Never happens. Putting a drag &amp;amp; drop interface on it doesn’t save
you from learning the database schema, so the job gets pushed to IT
anyway. Except now you’ve spent a packet on forcing a dumbed-down
interface on people who’d be happier with SQL and &lt;code&gt;git push&lt;/code&gt;. If we
assumed the report-reader was non-technical, but the &lt;em&gt;report-writer&lt;/em&gt; was
a geek, we could get the turnaround time on new reports down to less
than half an hour. And everyone would be happier.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chances of it happening&lt;/em&gt;: Unknown. I can see how to build it. I believe
it’s commercially viable. But I can’t see how to market it. That’s
something to mull.&lt;/p&gt;
&lt;h2 id=&quot;write-an-edn-parser-for-emacs&quot;&gt;Write an EDN Parser for Emacs&lt;/h2&gt;
&lt;p&gt;I’ve been playing around with a few CIDER tricks lately - such as &lt;a href=&quot;http://blog.jenkster.com/2013/12/a-cider-excursion.html&quot;&gt;this bind-a-Clojure-command&lt;/a&gt;
tip - to improve my Clojure-on-Emacs workflow. I could do some far
cooler stuff if Emacs could read Clojure data structures, and an EDN
parser’s the route to that.&lt;/p&gt;
&lt;p&gt;For instance, I’m thinking a much better org-babel/Clojure
integration&lt;sup&gt;&lt;a href=&quot;#user-content-fn-babel&quot; id=&quot;user-content-fnref-babel&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; for starters. After that, I’d love to have a
buffer that pretty-prints the value of an atom, watches it for
changes, and does some &lt;code&gt;watch&lt;/code&gt;-style syntax-highlighting for any diffs.
That would rock.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chances of it happening&lt;/em&gt;: Good. Geeky confession: I enjoy writing
parsers. And I’m always buggering around with Emacs these days, so
it’s probably just a matter of time.&lt;/p&gt;
&lt;h2 id=&quot;write-an-editor&quot;&gt;Write An Editor&lt;/h2&gt;
&lt;p&gt;If you’ve been here before you’ve probably gathered that I’m an editor
junkie, and there’s a constant pull to scratch my own itch. My ideal
editor would be a mashup of these principles:&lt;/p&gt;
&lt;h3 id=&quot;treat-the-user-like-a-programmer-the-way-emacs-does&quot;&gt;Treat The User Like A Programmer, The Way Emacs Does.&lt;/h3&gt;
&lt;p&gt;Why is Emacs the only programming tool that assumes you’ll want to
program it? Sure, almost every editor has some means of extension, but
Emacs really is in a different league. It opens on a “Program Me!”
buffer for chrissakes.&lt;/p&gt;
&lt;p&gt;(If you don’t believe Emacs is &lt;em&gt;uniquely&lt;/em&gt; extensible, check out my
video, &lt;a href=&quot;post:2013-10-08-writing-a-spotify-client-in-16-minutes&quot;&gt;Writing A Spotify Client in 16 Minutes&lt;/a&gt;.)&lt;/p&gt;
&lt;h3 id=&quot;treat-the-user-like-an-expert-the-way-vim-does&quot;&gt;Treat The User Like An Expert, The Way Vim Does.&lt;/h3&gt;
&lt;p&gt;For any tool you’ll use for 40 hours a week, for the next decade, the
initial learning curve is irrelevant. It’s how productive it makes you
after the first month that counts.&lt;/p&gt;
&lt;h3 id=&quot;treat-the-world-like-its-the-21st-century-the-way-lighttable-does&quot;&gt;Treat The World Like It’s The 21st Century, The Way LightTable Does.&lt;/h3&gt;
&lt;p&gt;In short, I would trade terminal support for an &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chances of it happening&lt;/em&gt;: Slim, sadly. Writing a good editor - and a
good one is the only kind I have any interest in writing - is a long,
long road. Unless it can pay its way, I’m going to have to resist
going down that rabbit hole.&lt;/p&gt;
&lt;h2 id=&quot;find-a-day-job&quot;&gt;Find A Day Job&lt;/h2&gt;
&lt;p&gt;2013 has been something of a sabbatical year for me. It’s been
fantastic for feeding my brain, but too isolated, and if I’m brutally
honest, a little navel-gazing. I’ve decided to &lt;a href=&quot;pdf:Kris_Jenkins_CV.pdf&quot;&gt;brush up my CV&lt;/a&gt; and
find some smart people to build interesting things with. I did a few
contracts last year, and there is something delightful about building
to spec. This year I’m going to dive in with both feet.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chances of it happening&lt;/em&gt;: Strong. Tell me if you know of any
interesting opportunities!&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-scala&quot;&gt;
&lt;p&gt;Okay, I tripped up &amp;amp; fell into Scala, but I got back up quickly. &lt;a href=&quot;#user-content-fnref-scala&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-babel&quot;&gt;
&lt;p&gt;Better than &lt;a href=&quot;http://blog.jenkster.com/2013/02/org-babel-clojure-and-nrepl.html&quot;&gt;this quick fix&lt;/a&gt; at least! &lt;a href=&quot;#user-content-fnref-babel&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Clojure On Emacs - A CIDER Workflow Hack</title><link>https://blog.jenkster.com/2013/12/a-cider-excursion.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/12/a-cider-excursion.html</guid><pubDate>Sat, 28 Dec 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;TLDR; In a few lines of Emacs Lisp, you can speed up your Clojure workflow, and it’s easy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Recently I’ve been experimenting with &lt;a href=&quot;https://github.com/clojure/tools.namespace&quot;&gt;clojure.tools.namespace&lt;/a&gt; and
&lt;a href=&quot;http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded&quot;&gt;Stuart Sierra’s Reloaded Workflow&lt;/a&gt;. If you haven’t read that post, you
should add it to your reading list. It’s a smart way of adding a
reset button to your REPL session, to ensure a clean environment
without having to restart the JVM.&lt;/p&gt;
&lt;p&gt;This post isn’t really about that workflow &lt;em&gt;per se&lt;/em&gt;, it’s just a good
use-case to demonstrate a little Emacs/Clojure/CIDER-fu.&lt;/p&gt;
&lt;p&gt;If you adopt that workflow, you’ll find yourself repeatedly typing
this into the REPL:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;clojure.tools.namespace.repl)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;clojure.tools.namespace.repl/refresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are a few ways to save that typing, but a little Emacs Lisp is
the most satisfying.&lt;/p&gt;
&lt;h2 id=&quot;its-simple&quot;&gt;It’s Simple&lt;/h2&gt;
&lt;p&gt;The easiest way in is to use the function &lt;code&gt;cider-interactive-eval&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; cider-namespace-refresh ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (cider-interactive-eval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;     &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(require &apos;clojure.tools.namespace.repl)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;      (clojure.tools.namespace.repl/refresh)&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;define-key&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; clojure-mode-map (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;kbd&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;M-r&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;&apos;cider-namespace-refresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;M-x cider-namespace-refresh&lt;/code&gt;, or simply &lt;code&gt;M-r&lt;/code&gt;, will run our Clojure
string and hit the reset button. Job done.&lt;/p&gt;
&lt;h2 id=&quot;its-reusable&quot;&gt;It’s Reusable&lt;/h2&gt;
&lt;p&gt;It doesn’t take much imagination to see how we can re-use this code.&lt;/p&gt;
&lt;p&gt;Say this afternoon’s development task means you’re going to be looking
at the value of an atom a lot. These few lines put viewing that atom a
single keystroke away:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;define-key&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; clojure-mode-map (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;kbd&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;M-r&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (cider-interactive-eval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;         &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(require &apos;[clojure.pprint :refer [pprint]])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;          (pprint @interesting-atom)&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s a recipe for a function you can set up in a heartbeat, and throw
away after a much zippier afternoon.&lt;/p&gt;
</content:encoded></item><item><title>Popup Help In Emacs Lisp</title><link>https://blog.jenkster.com/2013/12/popup-help-in-emacs-lisp.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/12/popup-help-in-emacs-lisp.html</guid><pubDate>Sat, 28 Dec 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you use Clojure &amp;amp; Emacs, you probably use &lt;code&gt;ac-nrepl-popup-doc&lt;/code&gt; to get
the docs for the thing under the point, in a temporary popup
window. And if you write any Elisp, you might be hankering for the
same thing for Emacs’ docs.&lt;/p&gt;
&lt;p&gt;Here’s some code that displays the same text as &lt;code&gt;describe-function&lt;/code&gt;, but
in a popup overlay:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;popup&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; describe-function-in-popup ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let*&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ((thing (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;symbol-at-point&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;         (description (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;save-window-excursion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;describe-function&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; thing)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;switch-to-buffer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;*Help*&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;buffer-string&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (popup-tip description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;point&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;point&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;around&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;scroll-bar&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; t&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code is actually fairly simple, so let’s break it down:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;symbol-at-point&lt;/code&gt; picks up the thing under the cursor, which should be
the function you’re hovering over.&lt;/p&gt;
&lt;p&gt;The shenannigens inside &lt;code&gt;save-window-excursion&lt;/code&gt; is just opening the
regular &lt;code&gt;describe-function&lt;/code&gt; window, snarfing its contents, and then
closing it immediately. That puts the help text in &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then we just call &lt;code&gt;popup-tip&lt;/code&gt; to display it. Here’s a screenshot:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/describe-function-popup.png&quot; alt=&quot;Popup Emacs Help&quot;&gt;&lt;/p&gt;
&lt;p&gt;You’ll probably want to set up your own favourite keybinding, but
here’s one example, binding it to &lt;code&gt;M-5&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;global-set-key&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;kbd&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;M-5&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;&apos;describe-function-in-popup&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;update&quot;&gt;Update&lt;/h2&gt;
&lt;p&gt;Thanks to a comment from &lt;a href=&quot;https://twitter.com/sanityinc&quot;&gt;Steve Purcell&lt;/a&gt;, we can refine this to work for
variables &amp;amp; faces, not just functions. The big change here is that we
replace &lt;code&gt;describe-function&lt;/code&gt; with &lt;code&gt;help-xref-interned&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; describe-thing-in-popup ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let*&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ((thing (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;symbol-at-point&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;         (help-xref-following &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;         (description (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;with-temp-buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;help-mode&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;help-xref-interned&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; thing)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                        (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;buffer-string&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (popup-tip description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;point&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;point&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;around&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;scroll-bar&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;               :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; t&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One of the nice things about this change is that help-xref lets us
supply our own temporary buffer, instead of re-using &lt;code&gt;*Help*&lt;/code&gt;. That
means we don’t clobber anything that’s currently in your help buffer.&lt;/p&gt;
&lt;p&gt;To take advantage of that, we just need to set &lt;code&gt;help-xref-following&lt;/code&gt; to
&lt;code&gt;t&lt;/code&gt;, and put the temp buffer in &lt;code&gt;help-mode&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Emacs - Reindent The Whole Buffer</title><link>https://blog.jenkster.com/2013/12/emacs-reindent-the-whole-buffer.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/12/emacs-reindent-the-whole-buffer.html</guid><pubDate>Thu, 26 Dec 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quite often in Emacs, especially when writing Clojure code, I want to
reindent the entire file. I think that arises from the fact that I’m
writing a lot of Lisp these days, and Lisp is the only language I’ve
ever encountered where automatic indenting actually works well.&lt;/p&gt;
&lt;p&gt;Anyway, here’s the code I use to map &lt;code&gt;meta-shift-q&lt;/code&gt; to “reindent the
whole buffer”:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; reindent-whole-buffer ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Reindent the whole buffer.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;indent-region&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;point-min&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                 (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;point-max&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;global-set-key&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;kbd&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;M-Q&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;&apos;reindent-whole-buffer&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty simple, huh?&lt;/p&gt;
</content:encoded></item><item><title>A Tip About Clojure&apos;s Less Than &amp; Greater Than Operators</title><link>https://blog.jenkster.com/2013/11/clojure-less-than-greater-than-tip.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/11/clojure-less-than-greater-than-tip.html</guid><pubDate>Wed, 27 Nov 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Although it initially takes some getting used to, I think
Clojure/Lisp’s prefix operators are a great idea. They make multi-argument
functions really easy, so you can say things like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; a b c)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…instead of the much-clunkier:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;javascript&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;a &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; b &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; b &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; c;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After a while you start to wonder why languages bother with operators
that are limited to two arguments.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt; variants are equally cool, as you can do things like
replace the classic range-check:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;javascript&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…with:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But in the early days, I found it hard to remember whether I wanted
&lt;code&gt;(&amp;lt; x 2)&lt;/code&gt; or &lt;code&gt;(&amp;gt; x 2)&lt;/code&gt;. For the simple pair, greater-than or less-than
just seemed to naturally belong in the middle, for the visual reminder.&lt;/p&gt;
&lt;p&gt;So here’s my mind-hack tip: Think of them as ‘getting-larger’ and
‘getting-smaller’ operators, and look at the shapes of the characters.&lt;/p&gt;
&lt;p&gt;The glyph &lt;code&gt;&amp;lt;&lt;/code&gt; is a triangle that starts small on the left and gets
larger as it goes right. &lt;code&gt;(&amp;lt; 2 x)&lt;/code&gt; is checking if the arguments start
small on the left, and get larger as you go right. Two is small, x is
larger.&lt;/p&gt;
&lt;p&gt;Similarly for &lt;code&gt;&amp;gt;&lt;/code&gt;. It starts large on the left of the shape &amp;amp; gets
smaller as it goes right.&lt;/p&gt;
&lt;p&gt;I found that helped the penny drop for me. Hopefully it’ll help a
reader or two…&lt;/p&gt;
</content:encoded></item><item><title>Dear Starbucks, I Like Clojure</title><link>https://blog.jenkster.com/2013/10/dear-starbucks-i-like-clojure.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/dear-starbucks-i-like-clojure.html</guid><pubDate>Wed, 23 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Starbucks,&lt;/p&gt;
&lt;p&gt;I like Clojure. It’s a relatively new JVM-based language in the family
of Lisp languages, which puts it in a heritage that’s practically as
old as programming itself.&lt;/p&gt;
&lt;p&gt;It favours modelling problems using simple, immutable data
structures - and let me tell you, once you’ve got used to immutable
data structures you’ll never want to go back to a language without
them.&lt;/p&gt;
&lt;p&gt;It uses a syntax that’s akin to writing your code directly as an AST,
which enables some very handy language features and editing tricks and
again, will be hard to give up once you’ve gotten used to it.&lt;/p&gt;
&lt;p&gt;And it has a REPL-driven development model that give you such a tight
feedback loop on your code it’s more like you’re having a conversation
with your computer - one that results in working code. It’s so much
fun.&lt;/p&gt;
&lt;p&gt;And that reaction you have right now, the one that says, “I’m glad
you’re happy, but I don’t know what you’re talking about and I don’t
really care so please just quietly get on with whatever you do best
without telling me the details ever again.”&lt;/p&gt;
&lt;p&gt;That’s how I feel when you ask me which kind of coffee bean I want.&lt;/p&gt;
</content:encoded></item><item><title>Getting the Bleeding Edge Build of an Emacs MELPA Package</title><link>https://blog.jenkster.com/2013/10/getting-the-bleeding-edge-build-of-an-emacsmelpa-package.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/getting-the-bleeding-edge-build-of-an-emacsmelpa-package.html</guid><pubDate>Tue, 15 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I learnt a great tip [Steve Purcell](&lt;a href=&quot;https://github.com/clojure-emacs/nrepl.el/issues/382&quot;&gt;https://github.com/clojure-emacs/nrepl.el/issues/382&lt;/a&gt;][here]] via [[&lt;a href=&quot;http://www.sanityinc.com/&quot;&gt;http://www.sanityinc.com/&lt;/a&gt;). If you want to get
the absolute latest build of an Emacs package, without waiting for the
MELPA rebuild cycle to take place, just:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone &lt;a href=&quot;https://github.com/milkypostman/melpa.git&quot;&gt;the Melpa repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;recipes/&lt;/code&gt; file in emacs.&lt;/li&gt;
&lt;li&gt;Accept the &lt;code&gt;dir-locals&lt;/code&gt; warning.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x package-build-current-recipe&lt;/code&gt; to evaluate that recipe locally and install the latest package.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I must remember that one…&lt;/p&gt;
</content:encoded></item><item><title>Using OAuth2 with Emacs</title><link>https://blog.jenkster.com/2013/10/an-oauth2-in-emacs-example.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/an-oauth2-in-emacs-example.html</guid><pubDate>Sun, 13 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been playing with the GitHub API, through Emacs. For all the
interesting stuff, it needs OAuth2 authorization, and though there’s
good support in Emacs for OAuth2, I couldn’t find a getting started
guide. So, here goes:&lt;/p&gt;
&lt;p&gt;First you’ll need an access token. The standard way of getting an
access token - redirect to the service (Github), authorize, redirect
back to your website - isn’t going to help us much. We don’t have a
website to come back to. It’s just an Emacs client.
But there’s an alternative, and all the providers I’ve played around
with so far support it. They’ll issue you an access token manually
for personal use.&lt;/p&gt;
&lt;p&gt;So, we head off to &lt;code&gt;Github &amp;gt; Account Settings &amp;gt; Applications&lt;/code&gt; and
there’s a box marked “Personal Access Tokens”. Creating one of those
gives us a token like &lt;code&gt;8914803c3f5038531dec13166ce098710c649281&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that magic string we’re away. Require the package (you may need
to &lt;code&gt;M-x package-install&lt;/code&gt; it first), then create an oauth2-token struct:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;oauth2&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; my-token&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (make-oauth2-token &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;access-token&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;8914803c3f5038531dec13166ce098710c649281&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that we turn to &lt;code&gt;oauth2-url-retrieve-synchronously&lt;/code&gt;. It will take
a token and a url and return a buffer containing the HTTP response. We
can dip into that buffer and read the JSON like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;json&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; user-data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;with-current-buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (oauth2-url-retrieve-synchronously my-token &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;https://api.github.com/user&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;goto-char&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; url-http-end-of-headers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;json-read&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Job done. Let’s just pull out an item:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;cdr&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;assoc&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;name&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; user-data))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Kris Jenkins&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s all there is to it. (Or at least, enough to get you started…)&lt;/p&gt;
</content:encoded></item><item><title>Finding Files In Emacs Helm</title><link>https://blog.jenkster.com/2013/10/finding-files-in-emacs-helm.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/finding-files-in-emacs-helm.html</guid><pubDate>Tue, 08 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Emacs’ &lt;a href=&quot;https://github.com/emacs-helm/helm&quot;&gt;Helm&lt;/a&gt; is awesome. (I’m on a bit of a helm kick this week). You
can [use it as a code-browser](&lt;a href=&quot;http://blog.jenkster.com/2013/10/writing-a-spotify-client-in-16-minutes.html&quot;&gt;http://blog.jenkster.com/2013/10/writing-a-spotify-client-in-16-minutes.html&lt;/a&gt;][use it to write a Spotify client]], you can [[&lt;a href=&quot;http://blog.jenkster.com/2013/10/a-tip-for-navigating-clojure-files-in-emacs.html&quot;&gt;http://blog.jenkster.com/2013/10/a-tip-for-navigating-clojure-files-in-emacs.html&lt;/a&gt;), but you can also use it for simple things like finding
files in a directory, tree or project.&lt;/p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;The setup’s pretty easy. You’ll want to install it of course:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;M-x&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; package-install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;helm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then edit your &lt;code&gt;~/.emacs&lt;/code&gt; and kick it off:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(helm-mode &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;
&lt;p&gt;Most helm stuff involves calling &lt;code&gt;(helm ...)&lt;/code&gt; function with some named
arguments. Once you’ve found the ones you want, you’ll want to bind it
to a shortcut key, but for now let’s try a basic invocation from the
scratch buffer.&lt;/p&gt;
&lt;p&gt;The two named arguments I use most are &lt;code&gt;:sources&lt;/code&gt; and &lt;code&gt;:buffer&lt;/code&gt;. &lt;code&gt;:sources&lt;/code&gt;
gives helm a list of places it can find search candidates. &lt;code&gt;:buffer&lt;/code&gt;
just names the buffer.&lt;/p&gt;
&lt;h2 id=&quot;some-searchy-examples&quot;&gt;Some Searchy Examples&lt;/h2&gt;
&lt;p&gt;So, a simple way to search for files under the current directory is:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(helm-source-findutils)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;        :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;*helm-findutils*&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’ll wait for you to enter at least 4 characters to narrow things
down, then present a list.&lt;/p&gt;
&lt;p&gt;We can add to that a few extra file-finding sources. If you
&lt;code&gt;package-install&lt;/code&gt; &lt;code&gt;helm-ls-git&lt;/code&gt;, you can search the git project for the
current file:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(helm-source-ls-git)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;        :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;*helm-find-git*&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you’re using Linux or OSX, you can search machine-wide through &lt;code&gt;locate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(helm-source-locate)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;        :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;*helm-locate*&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;mix--match&quot;&gt;Mix &amp;amp; Match&lt;/h2&gt;
&lt;p&gt;And rather cool, you can mix all three of these sources, in whichever
order you prefer:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(helm-source-findutils&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-ls-git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-locate)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;        :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;*helm-find-files*&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each section will be filtered separately, and you can jump between
them with &lt;code&gt;C-o&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-than-you-asked-for&quot;&gt;More Than You Asked For&lt;/h2&gt;
&lt;p&gt;And finally, here’s a kitchen sink example. Have a look at the names
of these sources and play around with any that sound useful:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(helm-source-findutils&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-recentf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-bookmarks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-buffers-list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-google-suggest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-locate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   helm-source-ls-git)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;        :&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;*helm all the things*&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And if that’s not enough, with helm enabled, &lt;code&gt;C-h v helm-source&lt;/code&gt; will
give you even more to digest…&lt;/p&gt;
</content:encoded></item><item><title>Writing a Spotify Client in 16 Minutes</title><link>https://blog.jenkster.com/2013/10/writing-a-spotify-client-in-16-minutes.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/writing-a-spotify-client-in-16-minutes.html</guid><pubDate>Tue, 08 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;iframe width=&quot;640&quot; height=&quot;480&quot; src=&quot;//www.youtube.com/embed/XjKtkEMUYGc&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;And the &lt;a href=&quot;https://github.com/krisajenkins/helm-spotify&quot;&gt;code is on Github&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Set An OSX Window To A Specific Size</title><link>https://blog.jenkster.com/2013/10/set-an-osx-window-to-a-specific-size.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/set-an-osx-window-to-a-specific-size.html</guid><pubDate>Mon, 07 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a handy tip: I wanted to set a terminal window to a specific
size, to check it was going to work on a projector later. This command
line does the trick:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; osascript&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;tell application &quot;terminal&quot; to set the bounds of the first window to {0, 0, 1280, 720}&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s &lt;code&gt;{left, top, right, bottom}&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>A Tip For Navigating Clojure Files in Emacs</title><link>https://blog.jenkster.com/2013/10/a-tip-for-navigating-clojure-files-in-emacs.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/10/a-tip-for-navigating-clojure-files-in-emacs.html</guid><pubDate>Wed, 02 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here’s a little Emacs trick I’ve starting using recently for
navigating Clojure. It’s an easy way to get a map of the file you’re
working on, and jump around it. Once it’s working, it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/helm-headlines.png&quot; alt=&quot;Helm Clojure Headlines&quot;&gt;&lt;/p&gt;
&lt;p&gt;To set it up, first you’ll need &lt;a href=&quot;https://github.com/emacs-helm/helm&quot;&gt;helm&lt;/a&gt;, so if you don’t have it
installed call:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;  M-x&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; package-install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;  helm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, stick this in your &lt;code&gt;.emacs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; helm-clojure-headlines ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Display headlines for the current Clojure file.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm-mode &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(((name &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Clojure Headlines&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    (volatile)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    (headline &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;^[;(]&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Eval it, and you’re away. &lt;code&gt;M-x helm-clojure-headlines&lt;/code&gt; will bring up the
map. You can type a string to narrow down the list. Hitting return
will leap to that point in the file. &lt;code&gt;C-n&lt;/code&gt; and &lt;code&gt;C-p&lt;/code&gt; will move through the
list of matches.&lt;/p&gt;
&lt;p&gt;How does it work? Mostly through Helm magic. All you really need to
think about is the:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(headline &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;^[;(]&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…part. That’s just a regular expression that tells helm which lines
in the file are headlines. For Clojure, I like “starts with a
semicolon or opening parenthesis”.&lt;/p&gt;
&lt;p&gt;For a more involved example, I use this version for Objective-C:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; helm-objc-headlines ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (helm &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;sources&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(((name &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Objective-C Headlines&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    (volatile)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                    (headline  &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;^[-+@]&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;|^#pragma mark&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A trickier regex, but still a very easy thing to setup for all it
supplies. And this trick works for any filetype you can think of a
sensible pattern to match against.&lt;/p&gt;
&lt;p&gt;Give it a whirl. If you like it, I leave it to you to bind your own
shortcut key. Oh, and you might like another, more complex thing I
built with helm: &lt;a href=&quot;https://github.com/krisajenkins/clojure-cheatsheet&quot;&gt;The Clojure Cheatsheet for Emacs&lt;/a&gt;. :-)&lt;/p&gt;
</content:encoded></item><item><title>Chicken, Chicken, Chicken</title><link>https://blog.jenkster.com/2013/08/chicken-chicken-chicken.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/08/chicken-chicken-chicken.html</guid><pubDate>Tue, 27 Aug 2013 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;chicken&quot;&gt;Chicken:&lt;/h2&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;[clojure.walk &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:as&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; walk]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;           &apos;[clojure.pprint &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:refer&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [pprint]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;           &apos;[clojure.string &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:refer&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [replace]])&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:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [form]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;walk/postwalk&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [x]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                     (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;cond&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x &apos;&amp;amp;) x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;string?&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x) (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;                                           #&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;\w&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;                                           &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;chicken&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol?&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x) &apos;chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;                      :else&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   form))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;chicken-chicken&quot;&gt;Chicken chicken:&lt;/h2&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;pprint&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  &apos;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; alter-map-values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;     &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Given a map, derive a new one where all the keys are passed through f.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;      If f returns nil, the key is unchanged.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     [f m]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [altered [k v]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;	       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;assoc&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; altered&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;		 k (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; v) v)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;	     {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;	     m))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;chicken-chicken-chicken&quot;&gt;Chicken, Chicken, Chicken:&lt;/h2&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;chicken chicken chicken, chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;  chicken chicken chicken chicken, chicken chicken chicken chicken.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [chicken chicken]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [chicken [chicken chicken]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; chicken chicken (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;chicken&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; chicken) chicken)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  chicken))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;chickens&quot;&gt;Chickens:&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=yL_-1d9OSdk&quot;&gt;Chicken&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.fogus.me/2013/07/17/an-introduction-to-deep-code-walking-macros-with-clojure/&quot;&gt;Chicken Chicken&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>West London Hack Night - August 2013</title><link>https://blog.jenkster.com/2013/08/west-london-hack-night-august-2013.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/08/west-london-hack-night-august-2013.html</guid><pubDate>Fri, 16 Aug 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Anonther &lt;a href=&quot;http://www.meetup.com/West-London-Hack-Night/events/130356642/&quot;&gt;West London Hack Night&lt;/a&gt;, and another success I’d say. We
picked a tough one this time: Write an interpreter and a virtual
machine in 90 minutes. That challenge was made both easier and harder
by the choice of language: &lt;a href=&quot;http://en.wikipedia.org/wiki/Brainfuck&quot;&gt;Brainfuck&lt;/a&gt;. It’s got a very simple
specification, but the language is so hard to read that debugging the
interpreter becomes a real brain…ache.&lt;/p&gt;
&lt;p&gt;By my count we mustered 20 people spread across 7 teams. Not everyone
managed to finish, but here are the projects that got published:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/denchev/brainfuck-php&quot;&gt;PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/Roysvork/6251663&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dpdawson/ruby-brainfuck&quot;&gt;Ruby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/funkotron/brainfuck&quot;&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/adamretter/Skullfuck&quot;&gt;Scala&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pljones/brain/blob/master/brainfuck.html&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not a bad result at all - almost everyone went home able to say they’d
implemented a Turing Complete programming language from scratch…&lt;/p&gt;
</content:encoded></item><item><title>Designing An Accounting System</title><link>https://blog.jenkster.com/2013/08/designing-an-accounting-system.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/08/designing-an-accounting-system.html</guid><pubDate>Tue, 06 Aug 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A fast thought on writing accounting software: The most common mistake
programmers make when writing an accounting system is they think it’s
all about balances. They think the point of an accounting system is to
tell you your account balance, so they design the data model around
that.&lt;/p&gt;
&lt;p&gt;They’re wrong. The point of an accounting system is to track the
complete history of the movements of money and other assets. Auditing
isn’t just a feature of the system, &lt;em&gt;it is the system&lt;/em&gt;. Balances are
just a summary report on the &lt;em&gt;real&lt;/em&gt; data.&lt;/p&gt;
</content:encoded></item><item><title>The Turing Rule</title><link>https://blog.jenkster.com/2013/08/the-turing-rule.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/08/the-turing-rule.html</guid><pubDate>Tue, 06 Aug 2013 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;If someone tries to end a debate about programming languages by
invoking Turing Equivalence, you are allowed to give them a long reel
of tape and steal their laptop.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If mathematical equivalence were the only thing that mattered in
language design, we’d all be using Turing tape. Turing Equivalence is
what qualifies a language to enter the debate, not what finishes it.&lt;/p&gt;
</content:encoded></item><item><title>Quote of the Day</title><link>https://blog.jenkster.com/2013/07/quote-of-the-day.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/07/quote-of-the-day.html</guid><pubDate>Thu, 18 Jul 2013 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Programmers talk about software development on weekends, vacations,
and over meals not because they lack imagination, but because their
imagination reveals worlds that others cannot see. - &lt;a href=&quot;https://en.wikiquote.org/wiki/Programming&quot;&gt;Thinking in C#&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>West London Hack Night - July 2013</title><link>https://blog.jenkster.com/2013/07/west-london-hack-night-july-2013.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/07/west-london-hack-night-july-2013.html</guid><pubDate>Sat, 13 Jul 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;[West London Hack Night](&lt;a href=&quot;http://www.meetup.com/West-London-Hack-Night/events/120495682/&quot;&gt;http://www.meetup.com/West-London-Hack-Night/events/120495682/&lt;/a&gt;][Last Thursday’s]] [[&lt;a href=&quot;http://www.meetup.com/West-London-Hack-Night/&quot;&gt;http://www.meetup.com/West-London-Hack-Night/&lt;/a&gt;) was great fun. The chosen topic
was Genetic Algorithms. More specifically, given a pool of random
strings, can you use GA to get them to evolve towards a target?&lt;/p&gt;
&lt;p&gt;It’s a simple application of a sophisticated idea, but perhaps a
perfect way to get started as you actually can code it up in about an
hour and a half.&lt;/p&gt;
&lt;p&gt;There were four teams hacking in four different languages, and here’s
their code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krisajenkins/javascriptgeneticalgorithm&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/oppianmatt/westlondonhack_20130711&quot;&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/t-ob/genetic&quot;&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CaffeinatedDave/GeneticAlgorithms&quot;&gt;Scala&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Great fun, as usual. I’m already looking forward to the next.&lt;/p&gt;
</content:encoded></item><item><title>Levenshtein Distance in Elisp</title><link>https://blog.jenkster.com/2013/06/levenshtein-distance-in-elisp.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/06/levenshtein-distance-in-elisp.html</guid><pubDate>Sun, 30 Jun 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here’s a quick implementation of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Levenshtein_distance&quot;&gt;Levenshtein distance&lt;/a&gt; - a measure
of the similiarity of two strings - in Emacs Lisp.&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;elisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;elisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; head (&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;substring&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; tail (&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;substring&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; levenshtein&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (string1 string2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;cond&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string1)) (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string2))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        ((&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string2)) (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; string1))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein (tail string1) string2) &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein string1 (tail string2)) &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein (tail string1) (tail string2))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;string-equal&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (head string1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                     (head string2))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;                       0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;                       1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Sunday&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Saturday&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Saturday&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Sunday&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;sitting&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;kitten&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (levenshtein &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;sitting&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;kittin&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note: I wrote this for interest’s sake, because I couldn’t sleep. If
you need a real implementation, you’d probably be better off with &lt;a href=&quot;http://www.emacswiki.org/emacs/levenshtein.el&quot;&gt;the one from EmacsWiki&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Solving Logic Puzzles With Clojure&apos;s Core Logic, Part Two</title><link>https://blog.jenkster.com/2013/02/solving-logic-puzzles-with-clojures-core-logic-part-two.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/solving-logic-puzzles-with-clojures-core-logic-part-two.html</guid><pubDate>Wed, 27 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.jenkster.com/2013/02/solving-logic-puzzles-with-clojures-corelogic.html&quot;&gt;In part one&lt;/a&gt; we laid the foundations for solving logic puzzles with
Clojure and &lt;code&gt;core.logic&lt;/code&gt;. We built a &lt;code&gt;core.logic&lt;/code&gt; query that encodes&lt;/p&gt;
&lt;p&gt;rules of this particular puzzle, and come up with a solution.&lt;/p&gt;
&lt;h1 id=&quot;the-rules&quot;&gt;The Rules&lt;/h1&gt;
&lt;p&gt;Let’s recap the rules:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Of Landon and Jason, one has the 7:30pm reservation and the other loves mozzarella.&lt;/li&gt;
&lt;li&gt;The blue cheese enthusiast subscribed to Fortune.&lt;/li&gt;
&lt;li&gt;The muenster enthusiast didn’t subscribe to Vogue.&lt;/li&gt;
&lt;li&gt;The 5 people were the Fortune subscriber, Landon, the person with a
reservation at 5:00pm, the mascarpone enthusiast, and the Vogue
subscriber.&lt;/li&gt;
&lt;li&gt;The person with a reservation at 5:00pm didn’t subscribe to Time.&lt;/li&gt;
&lt;li&gt;The Cosmopolitan subscriber has an earlier reservation than the mascarpone enthusiast.&lt;/li&gt;
&lt;li&gt;Bailey has a later reservation than the blue cheese enthusiast.&lt;/li&gt;
&lt;li&gt;Either the person with a reservation at 7:00pm or the person with a
reservation at 7:30pm subscribed to Fortune.&lt;/li&gt;
&lt;li&gt;Landon has a later reservation than the Time subscriber.&lt;/li&gt;
&lt;li&gt;The Fortune subscriber is not Jamari.&lt;/li&gt;
&lt;li&gt;The person with a reservation at 5:00pm loves mozzarella.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you look through them there are only really 5 &lt;em&gt;kinds&lt;/em&gt; of rule in
this puzzle, so we’ll group them and tackle them in order of
complexitye&lt;/p&gt;
&lt;h2 id=&quot;simple-facts&quot;&gt;Simple Facts&lt;/h2&gt;
&lt;p&gt;Rules (2) and (11) are the simplest:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* The blue cheese enthusiast subscribed to Fortune.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* The person with a reservation at 5:00pm loves mozzarella.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first we handle by saying, “one of the answers - and we don’t care
which one - has the shape &lt;code&gt;[* :fortune :blue-cheese *]&lt;/code&gt;. We handle &lt;code&gt;*&lt;/code&gt;
with an &lt;code&gt;(lvar)&lt;/code&gt;, and one-but-any-one with &lt;code&gt;membero&lt;/code&gt;, to give us this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;	&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The blue cheese enthusiast subscribed to Fortune.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :blue-cheese&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)] answers))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In English, &lt;code&gt;[* :fortune :blue-cheese *]&lt;/code&gt; is a member of the answer list.&lt;/p&gt;
&lt;p&gt;That’s fine, but I’ve a feeling we’re going to be writing &lt;code&gt;(lvar)&lt;/code&gt; a
lot, so for rule 11 we’ll start using
&lt;code&gt;clojure.tools.macro/symbol-macrolet&lt;/code&gt; for easier syntax:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;	&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The person with a reservation at 5:00pm loves mozzarella.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:mozzarella&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] answers)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;negated-facts&quot;&gt;Negated Facts&lt;/h2&gt;
&lt;p&gt;The second class of rules are negations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The muenster enthusiast didn’t subscribe to Vogue.&lt;/li&gt;
&lt;li&gt;The person with a reservation at 5:00pm didn’t subscribe to Time.&lt;/li&gt;
&lt;li&gt;The Fortune subscriber is not Jamari.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before we solve those, let’s take a look at a naive first-pass that tripped me up:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; BAD-rule-3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The muenster enthusiast didn&apos;t subscribe to Vogue.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;not-membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:vogue&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :muenster&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _] answers))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;not-membero&lt;/code&gt; isn’t a built-in function of &lt;code&gt;core.logic&lt;/code&gt;, but &lt;a href=&quot;http://stackoverflow.com/questions/11964055/constraining-two-vectors-to-be-in-the-same-domain-but-not-be-members-of-each-ot&quot;&gt;it’s easy enough to find&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sadly this doesn’t work. It looks like it’s saying, “Match a person
who likes Vogue and muenster cheese and make sure it’s not in the list
of answers.” But really it’s saying, “Is it possible to construct a
tuple that has Vogue and muenster, but &lt;em&gt;isn’t&lt;/em&gt; in the answer list?”
That answer to that is, yes. &lt;code&gt;[nil :vogue :muenster nil]&lt;/code&gt; would be
such a tuple. So the rule is trivially and always true. In effect, it
does nothing.&lt;/p&gt;
&lt;p&gt;No, to encode these rules correctly we need to say something about
what &lt;em&gt;is&lt;/em&gt; in the answer list, and then make extra assertions about
those things. We need to say, “There’s a tuple with Vogue, a tuple
with muenster, they’re both in the answer list but they aren’t the
same tuple.” Like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The muenster enthusiast didn&apos;t subscribe to Vogue.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [s1 s2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:vogue&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _] s1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:muenster&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _] s2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s1 answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s2 answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s1 s2))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That works. And note the use of &lt;code&gt;fresh&lt;/code&gt; to introduce the named, local logic variables (magic boxes) we need.&lt;/p&gt;
&lt;p&gt;Let’s encode the other two rules of this type:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The person with a reservation at 5:00pm didn&apos;t subscribe to Time.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [s1 s2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ _ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;] s1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:time&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _] s2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s1 answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s2 answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s1 s2))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The Fortune subscriber is not Jamari.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [s1 s2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _] s1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:jamari&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _ _] s2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s1 answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s2 answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; s1 s2))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;related-pairs&quot;&gt;Related Pairs&lt;/h2&gt;
&lt;p&gt;The third class of rules relate pairs of facts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Either the person with a reservation at 7:00pm or the person with
a reservation at 7:30pm subscribed to Fortune.”&lt;/li&gt;
&lt;li&gt;Of Landon and Jason, one has the 7:30pm reservation and the other loves mozzarella.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For these we can use &lt;code&gt;conde&lt;/code&gt; to make some OR statements. Here’s the code for the first rule:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Either the person with a reservation at 7:00pm or the person with a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;   reservation at 7:30pm subscribed to Fortune.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [r]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ r] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;conde&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                 [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;7.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is saying, “There’s an answer with Fortune in it, and I want to
make a further assertion about the reservation, so name it &lt;code&gt;r&lt;/code&gt;. My
further assertion is, &lt;code&gt;r&lt;/code&gt; is either 7pm or 7:30pm.”&lt;/p&gt;
&lt;p&gt;Fairly simple. And the next is only a little more complicated:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Of Landon and Jason, one has the 7:30pm reservation and the other loves mozzarella.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [c1 r1 c2 r2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:landon&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ c1 r1] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:jason&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ c2 r2] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;conde&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;           [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r1 &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;7.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; c2 &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:mozzarella&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;           [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r2 &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;7.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; c1 &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:mozzarella&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is saying, “There’s an answer with Landon in, and I want to make
some assertions about his choice of cheese &amp;amp; reservation. Ditto for
Jason&lt;sup&gt;&lt;a href=&quot;#user-content-fn-json&quot; id=&quot;user-content-fnref-json&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.” Then the assertions, “Either the first reservation
is 7:30pm and the second cheese is mozarella, or the other way
around.”&lt;/p&gt;
&lt;h2 id=&quot;mutual-exclusion&quot;&gt;Mutual Exclusion&lt;/h2&gt;
&lt;p&gt;Now we’re on to the home straight. The next class of rules - actually
there’s only one of them - is a description of five separate tuples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The 5 people were the Fortune subscriber, Landon, the person with
a reservation at 5:00pm, the mascarpone enthusiast, and the Vogue
subscriber.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The thing to notice here is that the rule’s really saying, whoever has
one trait in that list can’t have any of the others. So we can use
&lt;code&gt;permuteo&lt;/code&gt; again to describe all 5 tuples, allowing for the facts to
appear in any order:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The 5 people were the Fortune subscriber, Landon, the person with a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;   reservation at 5:00pm, the mascarpone enthusiast, and the Vogue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;   subscriber.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [[_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:landon&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _ _]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              [_ _ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              [_ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:mascarpone&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:vogue&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             answers)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;relative-facts&quot;&gt;Relative Facts&lt;/h2&gt;
&lt;p&gt;Okay, last class of rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Cosmopolitan subscriber has an earlier reservation than the mascarpone enthusiast.&lt;/li&gt;
&lt;li&gt;Bailey has a later reservation than the blue cheese enthusiast.&lt;/li&gt;
&lt;li&gt;Landon has a later reservation than the Time subscriber.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all very similar to the related pairs above, but with a
greater-than or less-than statement that makes things a little
tricker. Actually, it makes things much trickier, as we can’t just use
&lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt; in &lt;code&gt;core.logic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I’ve taken an easy way out here. If I say that the reservation times
are in strict order &lt;code&gt;[5 6 7 7.5 8.5]&lt;/code&gt;, then I can make greater-than
and less-than statements by saying one is to the left of another.&lt;/p&gt;
&lt;p&gt;I’ll define to-the-left-of as this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defne&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lefto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;x appears to the left of y in collection l.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [x y l]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ([_ _ [x . tail]] (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; y tail))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ([_ _ [_ . tail]] (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lefto&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; x y tail)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In English, “either x is the head of the list and y is a member of its
tail OR drop the head and recur.”&lt;/p&gt;
&lt;p&gt;With that helper in place, the next three rules should look pretty clear:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;The Cosmopolitan subscriber has an earlier reservation than the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;   mascarpone enthusiast.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [r1 r2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:cosmopolitan&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ r1] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:mascarpone&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r2] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lefto&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r1 r2 [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Bailey has a later reservation than the blue cheese enthusiast.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [r1 r2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ _ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:blue-cheese&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r1] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:bailey&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _ r2] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lefto&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r1 r2 [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; rule-9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Landon has a later reservation than the Time subscriber.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [answers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;symbol-macrolet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   [_ (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;fresh&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [r1 r2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [_ &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:time&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ r1] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;membero&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:landon&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; _ _ r2] answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;lefto&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; r1 r2 [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;take-it-home&quot;&gt;Take It Home&lt;/h1&gt;
&lt;p&gt;That’s it. Our driver function and our rules are all encoded. Running
it produces a list containing a single answer:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(((&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:amaya&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;  :fortune&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;      :blue-cheese&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:bailey&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :vogue&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;        :asiago&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;      8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:jamari&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :time&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;         :mascarpone&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;  6&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:jason&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;  :cosmopolitan&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mozzarella&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;  5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:landon&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :us-weekly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    :muenster&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;    7.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On my machine it takes about 1s to find the first answer, and about
16s to search exhaustively (and thus demonstrate that one answer is
all there is).&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://github.com/krisajenkins/LogicPuzzles&quot;&gt;find the code on GitHub&lt;/a&gt; if you want to give it a whirl.&lt;/p&gt;
&lt;p&gt;Thoughts? Questions? Suggestions? Leave a comment below…&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-json&quot;&gt;
&lt;p&gt;One of the hard parts of writing this code was typing Jason instead of JSON. &lt;a href=&quot;#user-content-fnref-json&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Solving Logic Puzzles With Clojure&apos;s Core Logic, Part One</title><link>https://blog.jenkster.com/2013/02/solving-logic-puzzles-with-clojures-corelogic.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/solving-logic-puzzles-with-clojures-corelogic.html</guid><pubDate>Wed, 27 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I used to love solving logic puzzles as a kid. Bought books of
’em. Great fun. They’re a puzzle with this sort of shape:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There are four sets of five things. For example, 5 people, 5
magazines, 5 reservation times and 5 cheeses.&lt;/li&gt;
&lt;li&gt;There are rules that connect them together, like, “Jason likes mozzarella.”&lt;/li&gt;
&lt;li&gt;The rules are exclusive. If we’re told Jason likes mozzarella, then
Jason likes no other cheese, and nobody else likes mozzarella.&lt;/li&gt;
&lt;li&gt;You are given enough clues about the relationships between these
things that only one possible configuration can exist. Find it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It cries out, “Logic Programming”, doesn’t it? Well, recently the
London Cloure group took a crack at it. We got pretty far, but didn’t
complete it before the night was over. I thought I’d finish it off and
write it up, for your pleasure. Here goes…&lt;/p&gt;
&lt;p&gt;I’ve taken a puzzle from &lt;a href=&quot;http://www.logic-puzzles.org/init.php&quot;&gt;Logic Puzzles.org&lt;/a&gt;, who seem to have a army of
them. Here are the sets of things we’re dealing with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;People&lt;/em&gt;: Amaya, Bailey, Jamari, Jason &amp;amp; Landon.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cheeses&lt;/em&gt;: Asiago, Blue Cheese, Mascarpone, Mozzarella &amp;amp; Muenster&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Magazines&lt;/em&gt;: Fortune, Time, Cosmopolitan, US Weekly &amp;amp; Vogue&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Reservation times&lt;/em&gt;: 5pm, 6pm, 7pm, 7:30pm, 8:30pm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here are the rules. You can skim over them. We’ll go through them
in detail in &lt;a href=&quot;post:2013-02-27-solving-logic-puzzles-with-clojures-core-logic-part-two&quot;&gt;part two&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Of Landon and Jason, one has the 7:30pm reservation and the other loves mozzarella.&lt;/li&gt;
&lt;li&gt;The blue cheese enthusiast subscribed to Fortune.&lt;/li&gt;
&lt;li&gt;The muenster enthusiast didn’t subscribe to Vogue.&lt;/li&gt;
&lt;li&gt;The 5 people were the Fortune subscriber, Landon, the person with a
reservation at 5:00pm, the mascarpone enthusiast, and the Vogue
subscriber.&lt;/li&gt;
&lt;li&gt;The person with a reservation at 5:00pm didn’t subscribe to Time.&lt;/li&gt;
&lt;li&gt;The Cosmopolitan subscriber has an earlier reservation than the mascarpone enthusiast.&lt;/li&gt;
&lt;li&gt;Bailey has a later reservation than the blue cheese enthusiast.&lt;/li&gt;
&lt;li&gt;Either the person with a reservation at 7:00pm or the person with a
reservation at 7:30pm subscribed to Fortune.&lt;/li&gt;
&lt;li&gt;Landon has a later reservation than the Time subscriber.&lt;/li&gt;
&lt;li&gt;The Fortune subscriber is not Jamari.&lt;/li&gt;
&lt;li&gt;The person with a reservation at 5:00pm loves mozzarella.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;There’s only one possible solution, and &lt;code&gt;core.logic&lt;/code&gt; is going to find it for us.&lt;/p&gt;
&lt;h2 id=&quot;before-we-start-whats-an-lvar&quot;&gt;Before We Start, What’s An &lt;code&gt;lvar&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;Imagine a closed box. I’ll tell you that inside the box is
something that is grey, weighs one tonne, and has a horn on its
nose. When we open the box, you won’t be surprised to see it
contains a rhino. That’s how I think of a logic variable, or
&lt;code&gt;lvar&lt;/code&gt;. It’s a box containing something that’s unknown right
now. We can state some rules about what must be inside, and when we
come to open the box, the right kind of thing will pop out.&lt;/p&gt;
&lt;p&gt;So, with that in mind, let’s set up our solution.&lt;/p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;/h2&gt;
&lt;p&gt;We’ll start with this code:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [people       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      magazines    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      cheeses      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      reservations (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      answers (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; list people magazines cheeses reservations)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;run*&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [q]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; q answers)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, we’ve done four things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Called the &lt;code&gt;lvar&lt;/code&gt; function five times, to create boxes for the five people.&lt;/li&gt;
&lt;li&gt;Repeated that three more times for magazines, cheeses and
reservations.&lt;/li&gt;
&lt;li&gt;Spliced those four lists together, using &lt;code&gt;(map list ...)&lt;/code&gt;, to
create a structure that’s a list of five &lt;code&gt;[person, magazine, cheese, reservation-time]&lt;/code&gt; tuples. When we open all those boxes, we’ll have
our answer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run&lt;/code&gt; a simple query: “Find all the qs, such that q is a possible answer.”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So far, so good. Now all we need to do is add the right
constraints, and the boxes will magically open to reveal the single
answer to the puzzle.&lt;/p&gt;
&lt;h2 id=&quot;first-constraints&quot;&gt;First Constraints&lt;/h2&gt;
&lt;p&gt;So the first thing we need to constrain is the list of people,
magazines, cheeses and reservations. This would be a start:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [people       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      magazines    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      cheeses      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      reservations (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      answers (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; list people magazines cheeses reservations)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [q]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; q answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; people [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:amaya&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :bailey&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :jamari&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :jason&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :landon&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; magazines [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :time&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :cosmopolitan&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :us-weekly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :vogue&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; cheeses [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:asiago&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :blue-cheese&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mascarpone&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mozzarella&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :muenster&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; reservations [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That says that &lt;code&gt;people&lt;/code&gt; matches the list of five names, but not
necessarily in the same order. It’s a permutation of the given
list. We repeat that pattern for all four kinds of thing.&lt;/p&gt;
&lt;p&gt;That’s almost right, but there’s a problem with ordering. Even once
we’ve figured out the correct tuples, we’re going to get them in
all possible orders, which is 5! or 120 answers, all of which are
equivalent.&lt;/p&gt;
&lt;p&gt;There are a few ways to handle this. We could to use a Set for the
answers, instead of a list. That would be good in theory, but
&lt;code&gt;core.logic&lt;/code&gt; doesn’t support sets&lt;sup&gt;&lt;a href=&quot;#user-content-fn-yet&quot; id=&quot;user-content-fnref-yet&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. We could ignore the
problem and just take whichever answer pops out first. Or we could
define a fixed order for any &lt;em&gt;one&lt;/em&gt; of the collections, and let the
others fall in line with that.&lt;/p&gt;
&lt;p&gt;Fixing the order is the approach I like, because then there’s only
one possible solution, which makes it easy to check we’ve got the
rest of the code right later. So let’s fix the order of the people:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [people       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      magazines    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      cheeses      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      reservations (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      answers (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; list people magazines cheeses reservations)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [q]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; q answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; people [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:amaya&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :bailey&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :jamari&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :jason&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :landon&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; magazines [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :time&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :cosmopolitan&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :us-weekly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :vogue&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; cheeses [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:asiago&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :blue-cheese&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mascarpone&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mozzarella&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :muenster&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; reservations [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And with that, we’re ready to start encoding puzzle rules. We’ll
pull them out as separate functions, so our final main function
will look like this:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [people       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      magazines    (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      cheeses      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      reservations (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeatedly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; lvar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      answers (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; list people magazines cheeses reservations)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [q]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; q answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; people [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:amaya&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :bailey&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :jamari&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :jason&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :landon&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-2&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-3&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-4&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-6&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-7&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-8&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-9&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-10&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;rule-11&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; answers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; magazines [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:fortune&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :time&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :cosmopolitan&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :us-weekly&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :vogue&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; cheeses [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:asiago&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :blue-cheese&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mascarpone&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :mozzarella&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; :muenster&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;permuteo&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; reservations [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8.5&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;])))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll look at the individual rules in &lt;a href=&quot;post:2013-02-27-solving-logic-puzzles-with-clojures-core-logic-part-two&quot;&gt;part two…&lt;/a&gt;&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-yet&quot;&gt;
&lt;p&gt;Yet. &lt;a href=&quot;#user-content-fnref-yet&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Writing Great Literature With Clojure</title><link>https://blog.jenkster.com/2013/02/writing-great-literature-with-clojure.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/writing-great-literature-with-clojure.html</guid><pubDate>Mon, 25 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Witness the might of lazy evaluation:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;[library.reference-section &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:as&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; reference])&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; complete-works-of-shakespeare&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; #(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; reference/complete-works-of-shakespeare %)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; typing (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;repeat&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; monkey))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thanks to lazy evaluation, an infinite number of monkeys can
be easily evaluated, even in memory-constrained environments&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;This technique can be used for any body of text for which you already have a reference copy. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Prolog Quote of the Day</title><link>https://blog.jenkster.com/2013/02/prolog-quote-of-the-day.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/prolog-quote-of-the-day.html</guid><pubDate>Fri, 22 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Prolog is a great language for writing append; after that it’s all downhill.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.paulgraham.com/arcchallenge.html&quot;&gt;Paul Graham&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m not saying I agree or disagree, but it’s a good line…&lt;/p&gt;
</content:encoded></item><item><title>Org Babel, Clojure and nREPL</title><link>https://blog.jenkster.com/2013/02/org-babel-clojure-and-nrepl.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/org-babel-clojure-and-nrepl.html</guid><pubDate>Thu, 21 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At the moment, org-babel’s Clojure evaluator assumes you’re running
swank. But if you’ve made the switch from swank to nREPL, that’s not
going to work. I bumped up against this problem this afternoon while
writing &lt;a href=&quot;https://blog.jenkster.com/2013/02/deepest-node-in-a-binary-tree.html&quot;&gt;this little Clojure-related blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Getting org-babel to use nREPL is easy enough though. I’ve just added this to &lt;code&gt;~/.emacs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;eval-after-load&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;ob-clojure&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  &apos;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; org-babel-execute:clojure (body params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;     &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;Execute a block of Clojure code with Babel and nREPL.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;nrepl&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (nrepl-current-connection-buffer)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;         (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ((result (nrepl-eval (org-babel-expand-body:clojure body params))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;           (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;car&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;read-from-string&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;plist-get&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;nREPL not connected!&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s just a first pass. It works, but I’m not sure I’m handling all the
options correctly, so I’ll let it sit here for a while until I’ve
given it enough exercise to be worth submitting back to the main
project. Still, you might find it useful. Any feedback would be appreciated. &lt;code&gt;:-)&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>Deepest Node In A Binary Tree</title><link>https://blog.jenkster.com/2013/02/deepest-node-in-a-binary-tree.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/deepest-node-in-a-binary-tree.html</guid><pubDate>Wed, 20 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Since a friend has just raised the question, “Find the deepest node in
a binary tree,” here’s my Clojure-flavoured answer:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; leaf?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [node]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;map?&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; node)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; deepest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  [node]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;leaf?&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; node)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; node]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [[depth leaf] (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;last&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;deepest&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:left&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; node))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                                      (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;deepest&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:right&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; node))]))]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;        [(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;inc&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; depth) leaf]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And here it is in action:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;deepest&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:left&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;          :right&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:left&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;:left&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;                         :right&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;                  :right&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;}})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| 3 | C |&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;His response? “It’s &lt;em&gt;a bit&lt;/em&gt; longer in C++.”&lt;/p&gt;
</content:encoded></item><item><title>A Vim Front-End for gDocs</title><link>https://blog.jenkster.com/2013/02/vim-google-docs.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/vim-google-docs.html</guid><pubDate>Wed, 20 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;tl;dr&lt;/em&gt; &lt;em&gt;Google Docs + Vim = Yay.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ah, the grail. Vim &lt;em&gt;everywhere&lt;/em&gt;. Once Vim’s got its claws in you, you
can’t settle for anything else. Every other editor is frustrating
and second-class.&lt;/p&gt;
&lt;p&gt;But for for Google Docs I’m forced to make an exception. It’s my ideal
way to work with normal people&lt;sup&gt;&lt;a href=&quot;#user-content-fn-geek&quot; id=&quot;user-content-fnref-geek&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Especially when it’s
changing a lot. Google Docs is user-friendly, it’s got all the
features we need, and no-one ever stops the conference call to say,
“Wait - did I email you the latest version?”&lt;/p&gt;
&lt;p&gt;But I still don’t want to give up Vim. How could we connect the two?
The way I see it, there are three possible solutions.&lt;/p&gt;
&lt;h2 id=&quot;vim-talks-to-google&quot;&gt;Vim talks to Google.&lt;/h2&gt;
&lt;p&gt;We could build a plugin for Vim that connects to the Google Docs
server. Ever since &lt;a href=&quot;http://googlewave.blogspot.co.uk/&quot;&gt;Google Wave&lt;/a&gt; came &amp;amp; went, there has been plenty of
information available on how to build a collaborative document-editing
system. We can assume that Google Docs approaches the problem along
these lines. The problem I think, wouldn’t be with the
protocol, but with Vim itself.&lt;/p&gt;
&lt;p&gt;Vim is single-threaded, so it’s not going to lend itself well to
listening asynchronously for changes from the central server. We could
probably work around that by reaching out from Vim into Python or
Ruby, but that instantly puts us into the realms of, “If this plugin
doesn’t work, simply re-compile your copy of Vim.” Yuck.&lt;/p&gt;
&lt;p&gt;Also, Vim has a strictly text-only display. Even if we could happily
listen for changes, displaying them is going to be tricky. We could
use some syntax-highlighting tricks to simulate multiple cursors, but
I think it’s always going to look like a hack.&lt;/p&gt;
&lt;p&gt;I don’t think building Google Docs collaborative editing into Vim is
impossible&lt;sup&gt;&lt;a href=&quot;#user-content-fn-existing&quot; id=&quot;user-content-fnref-existing&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, but I’m certain it would be swimming against the
tide. Getting it to work &lt;em&gt;well&lt;/em&gt; would be a mammoth project.&lt;/p&gt;
&lt;h2 id=&quot;maybe-emacs&quot;&gt;Maybe Emacs?&lt;/h2&gt;
&lt;p&gt;Emacs has a very good Vim-emulation mode, and copes well will multiple
processes and displaying text-with-extras&lt;sup&gt;&lt;a href=&quot;#user-content-fn-multiple&quot; id=&quot;user-content-fnref-multiple&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. It would be
possible. In fact, I’ve built a prototype myself, and whilst it’s not
releasable, it certainly proves the concept. But it puts us in an even
worse position: “To install this plugin, just install &lt;em&gt;Emacs&lt;/em&gt;.” I
can’t see any Vim user accepting that as a solution&lt;sup&gt;&lt;a href=&quot;#user-content-fn-emacs&quot; id=&quot;user-content-fnref-emacs&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;some-other-collaboration-service&quot;&gt;Some other collaboration service.&lt;/h2&gt;
&lt;p&gt;Another way forward would be to bypass both Vim &amp;amp; Google Docs for
something Vim-like and Google Docs-like, that’s better suited to the
task. There are a few online editors that offer collaboration, and
several of them are based on &lt;a href=&quot;http://codemirror.net/&quot;&gt;CodeMirror&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-codemirror&quot; id=&quot;user-content-fnref-codemirror&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;, which has a passable
Vi-emulation mode.&lt;/p&gt;
&lt;p&gt;This is probably the shortest path to a solution, but it still suffers
from our opening problem: You have to turn to your non-technical
colleagues and say, “Can we switch from Google Docs just so I can use
Vim?”, and they look at you like you’re an alien. No, the right
solution won’t involve having to change an existing team’s behaviour
just to accommodate our preferences.&lt;/p&gt;
&lt;h2 id=&quot;google-docs-becomes-vim-like&quot;&gt;Google Docs becomes Vim-like.&lt;/h2&gt;
&lt;p&gt;So the last solution, and I think the only viable one, is to graft a
Vim-like input system on top of Google Docs. If we do that, we don’t
have to disturb existing users, we ought to get live collaboration &amp;amp;
display for free, and we just have to worry about one key problem: How
much Vim do we need? How much would we have to implement before we
felt at home in Google Docs?&lt;/p&gt;
&lt;p&gt;Naive Vim extensions rarely seem to get much beyond &lt;code&gt;ESC, h, j, k, l&lt;/code&gt;
before they think they’ve got the essence of Vim. We know there’s
much more to it. With that in mind, here’s my list of what we’d need,
and a few things I think we can leave out:&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vim-like editing for Google Documents, without disturbing ordinary users.&lt;/li&gt;
&lt;li&gt;Support for:
&lt;ul&gt;
&lt;li&gt;Modal editing. (Normal, insert and visual modes).&lt;/li&gt;
&lt;li&gt;First-class motions &amp;amp; text objects. &lt;code&gt;d5j&lt;/code&gt; should delete 5 lines. &lt;code&gt;ci(&lt;/code&gt; should
change all the text in the current parentheses.&lt;/li&gt;
&lt;li&gt;Ex commands. Not a direct translation of the Vim ones, but
something like &lt;code&gt;:wordcount&lt;/code&gt; should trigger the word-count
box. &lt;code&gt;:help&lt;/code&gt; should trigger the Google Docs help.&lt;/li&gt;
&lt;li&gt;Custom keyboard mappings. Some equivalent to &lt;code&gt;nnoremap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Windowing commands remapped to switch between main, comment and sharing panes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;non-requirements&quot;&gt;Non-requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Plugins. Not for v1 at least.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I think it would be the right approach. I think it would be a
reasonably-sized project. I think it would make the world a better
place. So I’m putting the idea out into the world. What do you think?&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-geek&quot;&gt;
&lt;p&gt;Normal people. Non-geeks. People whom, I accept, shouldn’t be expected to learn Vim. &lt;a href=&quot;#user-content-fnref-geek&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-existing&quot;&gt;
&lt;p&gt;I should note that &lt;a href=&quot;http://blog.milford.io/2010/06/sweet-use-vim-with-google-docs/&quot;&gt;it’s possible to edit Google Documents with Vim&lt;/a&gt; using the &lt;a href=&quot;http://code.google.com/p/googlecl/&quot;&gt;Google Command Line&lt;/a&gt; tool. But that approach struggles with translating between gDocs’ format and plain text, and it doesn’t work collaboratively at all. &lt;a href=&quot;#user-content-fnref-existing&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-multiple&quot;&gt;
&lt;p&gt;[multiple cursors](&lt;a href=&quot;https://github.com/magnars&quot;&gt;https://github.com/magnars&lt;/a&gt;][Magnar Sveen]] of [[&lt;a href=&quot;http://emacsrocks.com/%5D%5BEmacs&quot;&gt;http://emacsrocks.com/][Emacs&lt;/a&gt; Rocks]] has a nice [[&lt;a href=&quot;https://github.com/magnars/multiple-cursors.el&quot;&gt;https://github.com/magnars/multiple-cursors.el&lt;/a&gt;) project
that would give some clues. &lt;a href=&quot;#user-content-fnref-multiple&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-emacs&quot;&gt;
&lt;p&gt;&lt;a href=&quot;post:2013-02-16-mapping-jk-in-emacs-evil-mode&quot;&gt;As I’ve written&lt;/a&gt;, these days Emacs is one of my favourite versions of Vim. But I don’t expect to convert anyone. (Hell, I’m not even certain I’d want to.) But if you like Vim &amp;amp; Lisp, it’s worth taking a look at &lt;a href=&quot;http://gitorious.org/evil/pages/Home&quot;&gt;Evil-mode&lt;/a&gt;. &lt;a href=&quot;#user-content-fnref-emacs&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-codemirror&quot;&gt;
&lt;p&gt;CodeMirror’s Vim-mode is far from perfect, but it wouldn’t be hard to make it much, much better. And the same thing goes for all the browser-based Vim emulations: Not good enough, but a good start. &lt;a href=&quot;#user-content-fnref-codemirror&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>A Simple Data Equation</title><link>https://blog.jenkster.com/2013/02/a-simple-data-equation.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/a-simple-data-equation.html</guid><pubDate>Sat, 16 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Take the number of copies you have of your data, and subtract
one. That’s how much your data matters to you.&lt;/p&gt;
</content:encoded></item><item><title>.emacs, To Start With</title><link>https://blog.jenkster.com/2013/02/emacs-to-start-with.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/emacs-to-start-with.html</guid><pubDate>Sat, 16 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This isn’t an original recipe, but this is how I kick off my .emacs
settings to ensure that &lt;code&gt;my-packages&lt;/code&gt; are auto-installed.&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;;;; Package magic.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;package-initialize&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;add-to-list&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;package-archives&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;(&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;melpa&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;http://melpa.milkbox.net/packages/&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defvar&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; my-packages &apos;(evil key-chord helm elscreen ace-jump-mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                           surround recentf magit)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;A list of packages to check for and install at launch.&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; my-missing-packages ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (missing-packages)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;dolist&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; my-packages missing-packages)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;package-installed-p&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; missing-packages)))))&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:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ((missing (my-missing-packages)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; missing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;    ;; Check for new packages (package versions)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;package-refresh-contents&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;    ;; Install the missing packages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;mapc&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFB86C;font-style:italic&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;package-installed-p&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;              (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;package-install&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; package&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          missing)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content:encoded></item><item><title>Mapping &quot;jk&quot; to Escape in Emacs&apos; evil-mode</title><link>https://blog.jenkster.com/2013/02/mapping-jk-in-emacs-evil-mode.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/mapping-jk-in-emacs-evil-mode.html</guid><pubDate>Sat, 16 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m a Vim user. But more &amp;amp; more these days I find that one of my
favourite versions of Vim is Emacs. Specifically, its &lt;code&gt;evil-mode&lt;/code&gt;
package, which is a very good Vim emulator&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;If you get started with &lt;code&gt;evil-mode&lt;/code&gt;, one of the first questions you
might ask is, “How do I remap ESC to something more finger-friendly?”
Some people like to map &lt;code&gt;jj&lt;/code&gt;. Personally I like &lt;code&gt;jk&lt;/code&gt;, because it rolls
off the fingers a little more easily.&lt;/p&gt;
&lt;p&gt;Anyway, there are a couple of ways to do it in Emacs. The simplest &amp;amp;
cleanest I’ve found is to install the &lt;code&gt;key-chord&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;M-x package-install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;key-chord&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…then add this to your &lt;code&gt;.emacs&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;key-chord&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(key-chord-mode &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(key-chord-define evil-insert-state-map  &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;jk&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;evil-normal-state&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Easy.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Actually, it’s the &lt;em&gt;only&lt;/em&gt; good Vim emulator/plugin I’ve ever encountered. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Today I Learnt...Something About Stack Overflow</title><link>https://blog.jenkster.com/2013/02/today_i_learnt.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/02/today_i_learnt.html</guid><pubDate>Tue, 12 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;…that the way &lt;a href=&quot;http://www.stackoverflow.com&quot;&gt;Stack Overflow&lt;/a&gt; detects
the syntax for a code-block is by looking at the tags on the
question. If your syntax-highlighting isn’t working, add the tag for
the language.&lt;/p&gt;
</content:encoded></item><item><title>Clojure Syntax Highlighting in Emacs</title><link>https://blog.jenkster.com/2013/01/clojure-syntax-highlighting-in-emacs.html</link><guid isPermaLink="true">https://blog.jenkster.com/2013/01/clojure-syntax-highlighting-in-emacs.html</guid><pubDate>Sat, 26 Jan 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So you’ve just written a new macro for your Clojure DSL, and now you
have something like:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defwidget&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; my-widget&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you’d love to add syntax highlighting to Emacs so that it gets
highlighted the way defn and defmacro do. Here are the magic words:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;;;; Adds new defn-esque keyword highlighting.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;add-hook&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;clojure-mode-hook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;          &apos;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;             (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;font-lock-add-keywords&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;                nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                &apos;((&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(defwidget&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;s-+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;w+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; font-lock-keyword-face&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;                   (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; font-lock-function-name-face&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;))))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s going on here? Well, let’s break it down:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;emacs-lisp&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;emacs-lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;;;; Add a function that runs for any Clojure buffer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;add-hook&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; &apos;clojure-mode-hook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;  ;; An anonymous function that takes no arguments.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  &apos;(&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#6272A4&quot;&gt;    ;; Set some new syntax-highlighting rules.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;font-lock-add-keywords&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; nil&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:#6272A4&quot;&gt;      ;; So many escape codes! But we&apos;re really just saying:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;      ;; Match the &apos;(&apos; character.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;      ;; Match and group the string &apos;defwidget&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;      ;; Match some whitespace. &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;s-+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;      ;; Match and group some word characters. &lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;w+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      &apos;((&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(defwidget&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;s-+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;w+&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&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:#6272A4&quot;&gt;            ;; The first regexp group is a keyword.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; font-lock-keyword-face&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#6272A4&quot;&gt;            ;; The second regexp group is a name.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;            (&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; font-lock-function-name-face&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&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:#F8F8F2&quot;&gt;      ))))) &lt;/span&gt;&lt;span style=&quot;color:#6272A4&quot;&gt;; Close up the patient.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content:encoded><category>clojure</category><category>programming</category><category>emacs</category></item><item><title>Lisp Quote of the Day</title><link>https://blog.jenkster.com/2012/12/lisp_quote_of_the_day.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/12/lisp_quote_of_the_day.html</guid><pubDate>Tue, 04 Dec 2012 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Why are macros so important to Lisp programmers? Not merely for the
syntactic convenience they provide, but because they are programs that
manipulate programs, which has always been a central theme in the Lisp
community. If FORTRAN is the language that pushes numbers around, and
C is the language that pushes characters and pointers around, then
Lisp is the language that pushes programs around.”&lt;/p&gt;
&lt;p&gt;Gabriel &amp;amp; Steele, The Evolution of Lisp.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An old quote, but still thoroughly relevant. (Though today you’d
probably pick something in place of Fortran, and add a note about Java
being the language that pushes objects around.)&lt;/p&gt;
</content:encoded><category>lisp</category><category>clojure</category><category>programming</category></item><item><title>Google Bootcamp Sarajevo</title><link>https://blog.jenkster.com/2012/11/google_bootcamp_sarajevo.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/11/google_bootcamp_sarajevo.html</guid><pubDate>Sun, 04 Nov 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Two weeks ago, I was invited to fly to Sarajevo and run a Google
Bootcamp. We debated about the content for a bit, and settled on a
training &amp;amp; hacking day around &lt;a href=&quot;http://www.angularjs.org&quot;&gt;AngularJS&lt;/a&gt;. A couple of hour-long talks
from me, and as much hacking as possible. Cue frantic writing of
slides.&lt;/p&gt;
&lt;p&gt;On Friday we flew there via Vienna - not quite believing it was real -
and yesterday they came, they saw &amp;amp; they hacked:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/google-bootcamp-sarajevo.png&quot; alt=&quot;Presenting at Google Bootcamp&quot;&gt;&lt;/p&gt;
&lt;p&gt;It was a &lt;em&gt;fantastic&lt;/em&gt; day. Everyone had great fun &amp;amp; got their brains
filled with new ideas. Me too.&lt;/p&gt;
&lt;p&gt;I’m still churning over the event in my mind, it’s still buzzing my
brain, so I can’t really write an elegant post about it yet. But if
you’ll indulge, here are a few random memories while they’re fresh:&lt;/p&gt;
&lt;p&gt;The attendees were great. Apparently there’s not really a tech scene
in Sarajevo like there is in London. Talks like this are a rare
thing. But everyone was straight in and hacking. There were some
really great ideas being hacked on &amp;amp; everyone was keen to learn. Geeks
of Sarajevo, I salute you.&lt;/p&gt;
&lt;p&gt;Doug Crockford - I stole some of your JavaScript jokes. I’m
sorry. JavaScript jokes are hard to write and you cornered the market
early. To make up for it I told people to use JSLint &amp;amp; buy your book.&lt;/p&gt;
&lt;p&gt;I met the President! Well, I met a President. The event was held at a
university, and the current Arch-Chancellor is the ex-President of
Bosnia. He gives good handshake.&lt;/p&gt;
&lt;p&gt;At the start of the day, they clipped a microphone on me and said,
“Say something while we check the levels.” Normal people say, “One
two. One two.” I recited The Owl &amp;amp; The Pussy Cat. Parenthood has
changed me.&lt;/p&gt;
&lt;p&gt;One of the local TV stations showed up and interviewed me. That was
weird. On a day like this, hackers come up to you and ask things like,
“How do you conditionally hide DOM elements generated by an ng-repeat
tag?&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;” But TV people ask you questions like, “What do you think
this means for Bosnia?” Under the circumstances, I think I switched
gear fairly smoothly. :-}&lt;/p&gt;
&lt;p&gt;As if we didn’t have enough to worry about, I decided that we’d
organize a couple of extra lightning talks. I figured on a day like
this it’s my job to throw as much information into people’s heads as I
possibly can. Amer - one of the guys helping me out - and I threw some
ideas onto a whiteboard, and people voted. Less and Hadoop won the
popular vote, so we each improvised 10 minutes of information. The
bonus talks seemed to go down really well. I’m glad we did it. (For
the record, I did the Less talk. That’s easy. You pretty much just
have to say, “Less exists!” and people get it. Less rocks. Less is
easy and it rocks.) (For the other record, I’d offered to do a Vim
Masterclass. It lost to Less by one vote. Sadface.)&lt;/p&gt;
&lt;p&gt;I love doing this kind of thing. It doesn’t matter if it’s a guitar or
a slideshow clicker in my hand, I like it. There’s a feeling that
comes upon you in the hours before the deadline. If you run away from
that feeling it’s called stagefright. If you run towards it it’s a
complete adrenaline rush. And speaking as a sedentary programmer who
hates sports, it’s rare that my body has reason to produce adrenaline.&lt;/p&gt;
&lt;p&gt;I wrote my own slideshow software. I’d normally scoff at such wheel
re-invention, but I really wanted to be able to show Angular working
live, within the slides, so I wrote an Angular slideshower that ran
Angular code inside my Angular slides&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. But on the morning of
the event I hit a minor crisis. The room was unexpectedly huge, and
they handed me a wifi clicker. I’d expected to be standing near my
laptop and hadn’t written clicker support into the code. To my relief
&amp;amp; amazement, I managed to hack it in in about 5 minutes. Say what you
like about JavaScript, but I couldn’t have done that in Java or
Objective-C half as fast.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Answer: Don’t. Filter the ng-repeat values up-front instead. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;It’s rough - I might find some time and polish it up into a real app - but you can see it here if you like. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded><category>clojure</category><category>programming</category><category>emacs</category></item><item><title>LISP vs Java</title><link>https://blog.jenkster.com/2012/11/lisp-vs-java.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/11/lisp-vs-java.html</guid><pubDate>Thu, 01 Nov 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is &lt;a href=&quot;http://en.wikiquote.org/wiki/Lisp&quot;&gt;quote of the day&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DOLIST is similar to Perl’s foreach or Python’s for. Java added a
similar kind of loop construct with the “enhanced” for loop in Java
1.5, as part of JSR-201. Notice what a difference macros make. A Lisp
programmer who notices a common pattern in their code can write a
macro to give themselves a source-level abstraction of that pattern. A
Java programmer who notices the same pattern has to convince Sun that
this particular abstraction is worth adding to the language. Then Sun
has to publish a JSR and convene an industry-wide “expert group” to
hash everything out. That process–according to Sun–takes an average
of 18 months. After that, the compiler writers all have to go upgrade
their compilers to support the new feature. And even once the Java
programmer’s favorite compiler supports the new version of Java, they
probably still can’t use the new feature until they’re allowed to
break source compatibility with older versions of Java. So an
annoyance that Common Lisp programmers can resolve for themselves
within five minutes plagues Java programmers for years.&lt;/p&gt;
&lt;p&gt;Peter Seibel, Practical Common Lisp.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So true. And that’s just for a language feature that everyone will
agree on. God help you if you want language feature in Java that’s
only useful to web developers.&lt;/p&gt;
</content:encoded></item><item><title>How To Make A Relational Database Schemaless</title><link>https://blog.jenkster.com/2012/07/how_to_make_a_relational_database_schemaless.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/07/how_to_make_a_relational_database_schemaless.html</guid><pubDate>Sat, 14 Jul 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just in case this isn’t completely obvious:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sql&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  CREATE&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; some_collection&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    id   &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; NOT NULL&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;    data&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; BLOB    &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;NOT NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There you go - you can serialize any key-value pair you like, without
a schema. Heck, the values don’t even have to be of the same type.&lt;/p&gt;
&lt;p&gt;You may or may not want to do this, but you can. My point is, while
there are many good things to say about NoSQL databases,
schemalessness isn’t the interesting one. Enforcing a schema is a
feature. Not enforcing one is not.&lt;/p&gt;
</content:encoded><category>sql</category><category>nosql</category></item><item><title>Programmers, Your Text Editor Wasn&apos;t Designed For You</title><link>https://blog.jenkster.com/2012/06/programmers-your-text-editor-wasnt.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/06/programmers-your-text-editor-wasnt.html</guid><pubDate>Wed, 06 Jun 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a programmer, the text editor is the core tool in your
world. Regardless of platform, language or environment, almost
everything you write will go through your editor of choice. And I’m
here to tell you folks: chances are, your text editor is the wrong
tool for the job. Here’s why….&lt;/p&gt;
&lt;p&gt;Most text editors are built to support a writer’s workflow. And a
writer’s workflow looks like this: Start a new document, append lots
of text, then later on, jump around a little &amp;amp; tweak:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/append-centric-editor.png&quot; alt=&quot;Append-Centric Editor&quot;&gt;&lt;/p&gt;
&lt;p&gt;The amount of jumping will vary depending on the writer, but the
workflow is essentially insert-centric. A tiny bit of time is spent
moving the cursor, the vast majority spent entering new text.&lt;/p&gt;
&lt;p&gt;And that’s the model that pretty much every text editor out there is
built on. Notepad &amp;amp; Word are built for writers, but so is the editor
in Eclipse, Xcode, IDEA &amp;amp; every other IDE I’ve ever seen. The workflow
is insert-centric, and any other features are just tacked onto a menu
at the top:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/fancy-insert-centric-editor.png&quot; alt=&quot;Fancy Insert-Centric Editor&quot;&gt;&lt;/p&gt;
&lt;p&gt;But we’re not writers! We’re programmers. Our workflow is completely
different. We spend very little time appending large chunks of new
text. We spend most of it jumping between functions, adding a bit
here, jumping there, deleting a few lines and moving them over to a
different file. We leap around, chopping, changing, expanding the code
all the day:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/manipulation-centric-editor.png&quot; alt=&quot;Manipulation-Centric Editor&quot;&gt;&lt;/p&gt;
&lt;p&gt;No editor designed for writers will ever support a workflow like that
well. And (almost) every editor is either designed for writers, or an
extension of one that was. Adding more menu items to a fundamentally
wrong workflow doesn’t solve the problem. We need an editor that isn’t
insert-centric. We need one that’s manipulation-centric. An editor
that assumes very little of our time will be spent inserting en-masse,
and that most of it will be spent jumping around, tweaking, expanding
and refining. We need an editor that assumes multiple files at once is
the norm. We need an editor that makes changing five scattered
sentences at least as easy as entering one new paragraph. The writer’s
editor will not achieve this, no matter how many menu items it has.&lt;/p&gt;
&lt;p&gt;If your editor sends you to a mouse to select a paragraph, it’s not
good enough. If it expects you to edit one file at a time, it’s not
good enough. If jumping between two related functions in two separate
files requires a mouse, it’s not good enough. In short, if your editor
doesn’t make movement a first-class citizen, it’s not good enough.&lt;/p&gt;
&lt;p&gt;There is at least one solution to this problem. There is at least one
editor that’s designed, from the ground up, for a programmer’s
workflow. But I’m trying to avoid mentioning it, because this post
isn’t about converting people to my favourite editor. It’s about the
fact that most editors aren’t designed for us, and that we need a
solution.&lt;/p&gt;
&lt;p&gt;There are two and a half types of editor. Editors designed for
writers. Editors designed for writers, with dozens of functions tacked
onto the menu system. And editors actually designed for
programmers. Whichever one you pick, please make sure you’ve picked it
deliberately.&lt;/p&gt;
&lt;p&gt;PS: Okay, my chosen editor is Vim. It addresses a programmer’s
workflow beautifully. But this isn’t a pro-Vim rant. It’s a workflow
plea. You don’t have to pick my solution, but I hope you see the
problem &amp;amp; go looking for a solution.&lt;/p&gt;
&lt;p&gt;PPS: Some of my colleagues think I’m anti-IDE. I’m not. I just keep
coming back to the editor. Having an Integrated Development
Environment is nice. Integration is a lovely thing. But having an
editor designed for programming is essential. I’ll give up integration
for that, every time.&lt;/p&gt;
</content:encoded></item><item><title>A Handy Clojure Macro For Development vs. Production</title><link>https://blog.jenkster.com/2012/03/handy-clojure-macro-for-development-vs.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/03/handy-clojure-macro-for-development-vs.html</guid><pubDate>Sat, 31 Mar 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here’s a quick little Clojure&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; macro I’ve started using.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.thebookfeed.com/&quot;&gt;The Book Feed&lt;/a&gt; is a new website I’ve put
together where you can write short book reviews, and optionally post
them to Facebook. When testing, I don’t want the post-to-Facebook code
to run while I’m developing, or my Facebook account would fill up with
test-data. It should really only run in production.&lt;/p&gt;
&lt;p&gt;That’s straightforward to code in any language. I write some kind of
&lt;code&gt;isLive()&lt;/code&gt; function, then wrap the relevant code in
&lt;code&gt;if ( isLive() ) {.... }&lt;/code&gt;. Easy, right?&lt;/p&gt;
&lt;p&gt;Well, in Clojure we can go one better. Take a look at this code:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defn&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; is-live? [] ...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; if-live [function &amp;amp; args]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;    `(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;is-live?&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;~function&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; ~@args)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;DEVELOPMENT Skipping:&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &apos;~function ~@args)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…then later in my code I replace:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;post-to-facebook&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; data1 data2 ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;…with:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;clojure&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;clojure&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;if-live&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; post-to-facebook data1 data2 ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At first glance this looks like syntactic sugar. It’s super-short, but
is it really any better than what we’d say in something like Java?&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;java&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;isLive&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;      postToFacebook&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(data1, data2, ...);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;      log.&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;DEVT Skipping: &lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; data1 &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E9F284&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; data2 ...);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, yes. This macro is significantly better, and not just because of
all the typing it saves. The &lt;code&gt;if-live&lt;/code&gt; macro has a magic property we’d
struggle to get in other languages: Instead of just skipping the code,
or printing a generic debugging message, it prints the exact code and
arguments it would execute were we in production. In other languages
we’re stuck with the tedious problem of keeping the log message &amp;amp; the
call in sync with each other&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;But because Clojure code can be treated as regular data, it’s trivial
to print the call instead of executing it. With no effort, I can see
exactly what the call would send to Facebook, without worrying about
keeping the debug message in sync with the function call.&lt;/p&gt;
&lt;p&gt;Yay macros.&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Everything in this post is applicable to LISPs in general. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;I can think of a few workarounds for a couple of languages, but nothing that comes close to the elegance of this macro. Nothing that says, “Add these 8 characters to any function and it just works.” &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>It&apos;s Complicated</title><link>https://blog.jenkster.com/2012/03/its_complicated.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/03/its_complicated.html</guid><pubDate>Tue, 20 Mar 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This evening I saw a man who was incredibly buff. Take the fittest
I’ll ever be in my life, and he was far, far fitter at 60. He was so
toned he could easily have been a world-class yoga teacher. He wasn’t
a world-class yoga teacher. He was a world-class musician. He was
Sting.&lt;/p&gt;
&lt;p&gt;Sometimes I feel inadequate.&lt;/p&gt;
&lt;p&gt;I pray to God.&lt;/p&gt;
&lt;p&gt;I say, “God, sometimes I feel inadequate.”&lt;/p&gt;
&lt;p&gt;“That’s okay,” says God. “That’s why I created Tom Jones. He’s being
awesome enough for everyone.”&lt;/p&gt;
&lt;p&gt;He’s right.&lt;/p&gt;
&lt;p&gt;“Have a Gin &amp;amp; Tonic,” says God.&lt;/p&gt;
&lt;p&gt;He’s right again.&lt;/p&gt;
</content:encoded></item><item><title>Letters to Juliet, A Film Review</title><link>https://blog.jenkster.com/2012/03/letters-to-juliet-film-review.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/03/letters-to-juliet-film-review.html</guid><pubDate>Mon, 05 Mar 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just in case you’re tempted to watch this film, let me save you the
bother and tell you what happens:&lt;/p&gt;
&lt;p&gt;Gael Garcia Bernal plays, ‘The only person in the film with an ounce
of charisma.’ He is engaged to a blonde personality vacuum with bad
dress sense. They fly to Verona. He runs off to do interesting things,
we are forced to stay in the hotel and watch her pout.&lt;/p&gt;
&lt;p&gt;After an hour of tedium, Ms Airhead finds the man she’s been looking
for. She is overjoyed. His soulless husk is as badly dressed as
hers. He is overjoyed too. He hasn’t had any real work since he left
Home &amp;amp; Away.&lt;/p&gt;
&lt;p&gt;Vanessa Regrave picks up a cheque, a free holiday in Italy, and a kiss
from Italy’s answer to Tom Jones. Given how little screen time is
given to septuagenarian nookie these days, she chalks the film up as a
personal victory.&lt;/p&gt;
&lt;p&gt;The End.&lt;/p&gt;
</content:encoded></item><item><title>How Do I Pick The Wrong Programming Language?</title><link>https://blog.jenkster.com/2012/02/how-do-i-pick-wrong-programming.html</link><guid isPermaLink="true">https://blog.jenkster.com/2012/02/how-do-i-pick-wrong-programming.html</guid><pubDate>Sun, 12 Feb 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A little thought experiment has been running around in my head for the
past couple of days. I thought I’d share it with you.&lt;/p&gt;
&lt;p&gt;It’s very hard to rank programming languages. We get a sense that some
are good &amp;amp; some are bad, but the more experience you have the more
caveats you have to allow: X is good (but it’s hard to find good X
programmers); Y is fairly bad (but it’s good for data-wrangling),
etc. Choosing the right language for the job is an art. But, as a
novel way of looking at the problem, here’s my thought experiment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There’s a 5-year project coming up. You don’t know what it is. You
don’t know how many programmers will be working on it, or how good
they’ll be. You know nothing, except that it must be fairly large
because it’s a 5-year project.&lt;/p&gt;
&lt;p&gt;You have one choice, and one objective. You get to choose the
programming language for the project. And your objective is to
guarantee that at the end of five years, the code-base is a sprawling,
hideous, unmaintainable nightmare.&lt;/p&gt;
&lt;p&gt;Which language do you pick?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You’re not allowed to cheat. You have to pick a language you’d use for
a real project. You can’t choose assembly language, and you certainly
can’t choose &lt;a href=&quot;http://en.wikipedia.org/wiki/Brainfuck&quot;&gt;Brainfuck&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think this is an interesting way of thinking about the question for
two reasons. First, whilst we spend so much of our time as programmers
maintaining code, we spend surprisingly little time talking about
maintenance. Or thinking about it. And second, the question isn’t,
“Which is the least maintainable language?”, but rather, “Which
languages tends to encourage the least maintainable behaviour?”&lt;/p&gt;
&lt;p&gt;I think I’ve made my choice. I think I’m picking Perl.&lt;/p&gt;
&lt;p&gt;Now don’t get me wrong, I like Perl a lot. I seem to like Perl more
than most people I meet. It’s particularly strong at text-handling,
and makes a good choice when you’re forced to resort to
screen-scraping semi-structured data.&lt;/p&gt;
&lt;p&gt;But Perl does not lend itself well to large, clear code bases. It has
a good object model, but it doesn’t enforce it. It doesn’t even really
recommend it. It’s just there in case anyone’s interested.&lt;/p&gt;
&lt;p&gt;It has something like a recommended project structure, but unless
you’re producing modules for CPAN or you’ve stumbled upon the object
model, you’ll probably miss it.&lt;/p&gt;
&lt;p&gt;And worst of all there’s very little unity of approach. Ask five Java
programmers to write a simple program, and by-and-large all five of
them will come up with a similar answer. Ask five Perl programmers,
and they’ll all have a different preferred approach. And they’ll
probably all take pride in how novel their solution is. That’s all
good fun, but having five ways to do the same simple thing doesn’t
lend itself to large scale coding.&lt;/p&gt;
&lt;p&gt;I could pick other languages. The worst coding crimes I’ve ever seen
have all been in PHP. But for an absolute lack of unity, I’m picking
Perl.&lt;/p&gt;
&lt;p&gt;What would you pick?&lt;/p&gt;
</content:encoded></item><item><title>Naming Things</title><link>https://blog.jenkster.com/2011/11/naming-things.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/11/naming-things.html</guid><pubDate>Sun, 06 Nov 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday we went to a toy store called Fun Junction. I think this is
a terrible name. To me, Fun Junction is the point where Fun &amp;amp; No Fun
meet…&lt;/p&gt;
</content:encoded></item><item><title>Because the Kids are Lighting Fireworks Already</title><link>https://blog.jenkster.com/2011/11/because-kids-are-lighting-firework.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/11/because-kids-are-lighting-firework.html</guid><pubDate>Thu, 03 Nov 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Remember, remember the 3rd of November,
Blowing things up is a lark,
I don’t care a jot about gunpowder plot,
I’m off to light fires in the park…&lt;/p&gt;
</content:encoded></item><item><title>Internet Explorer to Enter the Deadpool</title><link>https://blog.jenkster.com/2011/09/internet-explorer-to-enter-deadpool.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/09/internet-explorer-to-enter-deadpool.html</guid><pubDate>Sun, 04 Sep 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In a surprise move, Microsoft have today announced that they’re
getting out of the browser game. “It’s time to call it a day,” said a
Microsoft spokesperson. “We’ve been working on Internet Explorer for
over fifteen years now,
and
&lt;a href=&quot;http://37signals.com/svn/posts/2988-i-thought-internet-explorer-9-was-supposed&quot;&gt;we still can’t render basic layouts reliably&lt;/a&gt;.”&lt;/p&gt;
&lt;p&gt;“‘Does it work in IE yet?’ has become a stock question for web
developers around the globe, and it’s getting embarrassing.”&lt;/p&gt;
&lt;p&gt;“It’s time we left the browser game to the professionals, and focussed
on what we’re good at: rearranging the menu bar in Word every 6
months.”&lt;/p&gt;
</content:encoded></item><item><title>How To Get X11 Working On An EC2 AMI</title><link>https://blog.jenkster.com/2011/08/how-to-get-x11-working-on-ec2-ami.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/08/how-to-get-x11-working-on-ec2-ami.html</guid><pubDate>Wed, 17 Aug 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s actually pretty easy, but worth noting:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;sh&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ec2-user@ec2machine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; yum&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; xauth&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; xeyes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt;exit&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:#50FA7B&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -X&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; ec2-user@ec2machine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;xeyes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In short, the magic’s in installing Xauth and then re-logging in with
the &lt;code&gt;ssh -X&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;And I admit, xeyes isn’t strictly necessary, but I find it’s a nice,
lightweight confirmation that both display and mouse are working as
expected.&lt;/p&gt;
</content:encoded></item><item><title>Diagnosing Problems On The Web - A Rule Of Thumb</title><link>https://blog.jenkster.com/2011/08/diagnosing_problems_on_the_internet.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/08/diagnosing_problems_on_the_internet.html</guid><pubDate>Wed, 03 Aug 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My mother is asking for technical support ‘for a friend’. She’s
reminded me of this quick diagnostic tip that’s worth noting:&lt;/p&gt;
&lt;div class=&quot;code-block-wrapper&quot;&gt;&lt;div class=&quot;code-block-header&quot;&gt;&lt;span class=&quot;code-language&quot;&gt;plaintext&lt;/span&gt;&lt;button class=&quot;code-copy-btn&quot; type=&quot;button&quot; data-copy=&quot;true&quot;&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Geek: What browser are you using?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Patient: What&apos;s a browser?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;They’re using Internet Explorer. Someone might have installed a better
browser for them, but if they had someone like that in their lives,
they wouldn’t turn to you for tech support.&lt;/p&gt;
</content:encoded></item><item><title>Vim vs. Emacs - The War Is Over</title><link>https://blog.jenkster.com/2011/08/vim-vs-emacs-war-is-over.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/08/vim-vs-emacs-war-is-over.html</guid><pubDate>Mon, 01 Aug 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Vim is the greatest text editor in the
world.
&lt;a href=&quot;https://blog.jenkster.com/2012/06/programmers-your-text-editor-wasnt.html&quot;&gt;I have strong opinions about why this is so&lt;/a&gt;,
and why Eclipse &amp;amp; co.’s editors are inadequate by design, but that’s
for another day. No, this is just a quick post to say the Vim
vs. Emacs wars are over. I’m a Vim user, but if you like Emacs that’s
just fine with me. We mustn’t fight. We must save our energy. There
are people out there writing code in Notepad FFS…&lt;/p&gt;
</content:encoded></item><item><title>Star Pelican</title><link>https://blog.jenkster.com/2011/07/star-pelican.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/07/star-pelican.html</guid><pubDate>Sat, 30 Jul 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; I’m blogging again. Certainly the current frequency of posts
would imply I am. And if I’m blogging again, I’m doing it because
there are thoughts that are too public for Facebook &amp;amp; too long for
Twitter. Thoughts like,
“&lt;a href=&quot;https://blog.jenkster.com/2011/07/native-apps-vs-web-apps.html&quot;&gt;Google’s webapps are so good that they show webapps are doomed.&lt;/a&gt;”
And non-technical thoughts too, like, “In the future, Pelicans will be
armed.”&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/star-pelican.jpg&quot; alt=&quot;Star Pelican&quot;&gt;&lt;/p&gt;
</content:encoded><category>osx</category><category>apps</category><category>geek</category></item><item><title>Native Apps vs Web Apps</title><link>https://blog.jenkster.com/2011/07/native-apps-vs-web-apps.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/07/native-apps-vs-web-apps.html</guid><pubDate>Fri, 29 Jul 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An interesting question at the moment is, should I build native iOS &amp;amp;
Android apps, or build one webapp to rule them all? There are pros and
cons to each. Most of the arguments are obvious and well-trodden, but
here’s one point that’s important and not being said: Google.&lt;/p&gt;
&lt;p&gt;Google have put their stake in the ground and are investing heavily in
the webapp route. Their Gmail &amp;amp; Google+ clients are are easily the
most advanced mobile webapps in the game. And do you know what?
They’re still a bit rubbish. They’re a bit slow. They’re a bit
flakey. They all have the, “This looked really good in the lab”, feel
to them.&lt;/p&gt;
&lt;p&gt;Google’s webapps are “impressive, for a webapp”, which is like saying,
“he’s cool, for a geek”. A qualified compliment isn’t much of a
compliment at all. I really want them to succeed, and they’re doing an
amazing job, but for all their effort I still go to the app store to
find the &lt;em&gt;real&lt;/em&gt; app.&lt;/p&gt;
&lt;p&gt;If Google, with all their talent and resources, can push the
possibilities of webapps and we still need to offer excuses, maybe
that says it’s not the way to go…&lt;/p&gt;
</content:encoded><category>webapps</category><category>native</category><category>apps</category><category>iphone</category><category>android</category><category>geek</category></item><item><title>London 2012, One Year To Go</title><link>https://blog.jenkster.com/2011/07/london-2012-one-year-to-go.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/07/london-2012-one-year-to-go.html</guid><pubDate>Wed, 27 Jul 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow! I just found out I’ve been elected as Chairman Of The Olympic
Committee For Getting People Who Don’t Give A Stuff About The Olympics
To Give A Stuff About The Olympics.&lt;/p&gt;
&lt;p&gt;My first campaign will be, “Come To London in 2012: The Aquarium Will
Still Be Ace.”&lt;/p&gt;
&lt;p&gt;I’ll follow up with my second campaign, “Enjoyed The Aquarium? You
Could Watch Some Humans Swim Next, I Suppose.”&lt;/p&gt;
</content:encoded></item><item><title>OSX Apps I Can&apos;t Live Without</title><link>https://blog.jenkster.com/2011/07/osx-apps-i-cant-live-without.html</link><guid isPermaLink="true">https://blog.jenkster.com/2011/07/osx-apps-i-cant-live-without.html</guid><pubDate>Wed, 27 Jul 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Frabjous day - I have a new laptop. I’d been waiting for ages for the
next model of MacBook Air to be released, so I pounced at the
weekend. And I think that makes it time for the geekblogger’s
favourite: the “OSX Apps I Install First” list. I’ll avoid the obvious
ones like Chrome, Spotify, Dropbox &amp;amp; XCode, and skip straight to the
meat. Hopefully there’s something here you haven’t heard of before
that you can try…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.alfredapp.com/&quot;&gt;Alfred&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Do you like Terminal, Spotlight or Chrome’s universal search feature?
Then Alfred is for you. It’s a fast app-launcher, file-finder &amp;amp;
web-searcher that’s absolutely the first thing I put on every
Mac. More flexible than Spotlight, faster than QSB and currently
thriving (unlike the almost-zombie Quicksilver), I can’t recommend it
enough.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/alfred-logo-small.png&quot; alt=&quot;Alfred Logo&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.backblaze.com/partner/af4609&quot;&gt;Backblaze&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We were burgled last year. My laptop - my working life - was taken. I
had Time Machine backups, and I got lucky (they didn’t steal my
external hard drive) so I got it all back. But never again will I risk
my music &amp;amp; my photos&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; on the laziness of thieves.&lt;/p&gt;
&lt;p&gt;In the weeks following the burglary I tried several off-site backup
solutions&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. BackBlaze is the bee’s knees. It’s written by ex-Apple
employees, and it shows. Actually, it hides. It just sits quietly in
the background ensuring that my data’s always backed up to a second
country. It also does second duty as a poor man’s version control
system, and third duty as a find-if-stolen service. But it’s
absolutely, 100% worth the price of a latte a month. Get it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/backblaze-logo-small.jpg&quot; alt=&quot;Backblaze Logo&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.pixelmator.com/&quot;&gt;Pixelmator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’m not a graphic designer. I’ll never be a graphic designer. So I
can’t tell you exactly how Pixelmator compares to Photoshop. I can
tell you that it does more than everything I need, it’s about 95%
cheaper than Photoshop, and it’s one of the most polished pieces of
software I’ve ever used.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/pixelmator-logo-small.png&quot; alt=&quot;Pixelmator Logo&quot;&gt;&lt;/p&gt;
&lt;p&gt;My ‘hobby’ iPad app, &lt;a href=&quot;http://itunes.jenkster.com/time-for-tea&quot;&gt;Time for Tea&lt;/a&gt;, was
designed in Pixelmator and I think the result is pretty good (for a
non-graphic designer):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.jenkster.com/files/time_for_tea_ipad.png&quot; alt=&quot;Time for Tea&quot;&gt;&lt;/p&gt;
&lt;p&gt;(That’s the current peak of my design skills. Any shortcomings are mine, not Pixelmator’s.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Of course all my work is backed up again to remote git repositories, but you guessed that, right? &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Mozy sucks, by the way. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded><category>osx</category><category>apps</category><category>geek</category></item></channel></rss>