<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>DaFoster (Software)</title>
 <link href="https://dafoster.net/articles/topics/#Software"/>
 <link href="https://dafoster.net/articles/topics/Software.xml" rel="self"/>
 <updated>2026-05-01T03:44:48+00:00</updated>
 <id>https://dafoster.net/articles/topics/#Software</id>
 <author>
   <name>David Foster</name>
   
 </author>
 <icon>https://dafoster.net/favicon.ico</icon>
 <logo>https://dafoster.net/favicon.ico</logo>

 
 
 <entry>
   <id>https://dafoster.net/articles/2026/04/17/ai-attribution-in-git</id>
   <title>AI Attribution in Git</title>
   <published>2026-04-17T00:00:00+00:00</published>
   <updated>2026-04-17T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2026/04/17/ai-attribution-in-git/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;When making a git commit I&amp;rsquo;ve been looking for a way to record what AI model or coding agent harness I used to help me write the commit, ideally in a machine-readable way.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;AI-drafted code that I&amp;rsquo;ve reviewed&lt;/strong&gt; or &lt;strong&gt;self-drafted code with significant AI revisions&lt;/strong&gt;, I add one of the following trailers to my git commit message:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Co-authored-by: Claude Opus 4.6 &amp;lt;noreply@anthropic.com&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Co-authored-by: Claude Sonnet 4.6 &amp;lt;noreply@anthropic.com&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Co-authored-by: Claude Haiku 4.5 &amp;lt;noreply@anthropic.com&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Co-authored-by: GPT-5.3-Codex &amp;lt;noreply@openai.com&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Co-authored-by: Google Gemini 3.1 Flash Image (Nano Banana 2)&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;TODO: Identify an email address to use for Gemini&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;blockquote&gt;&lt;p&gt;Tip: I use &lt;a href=&quot;https://www.typesnap.app/blog/mac-text-replacement-guide/&quot;&gt;text expansion macros&lt;/a&gt; like &lt;code&gt;coa → &quot;Co-authored-by: &quot;&lt;/code&gt; and &lt;code&gt;aco → &quot;Claude Opus 4.6 &amp;lt;noreply@anthropic.com&amp;gt;&quot;&lt;/code&gt; to type those trailers quickly.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;For &lt;strong&gt;AI-drafted code that I&amp;rsquo;ve NOT reviewed&lt;/strong&gt; (rare; mostly for internal or one-off tools):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author = one of the emails above, via &lt;code&gt;git commit --author=&quot;AI Model &amp;lt;noreply@example.com&amp;gt;&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Co-authored-by = me:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Co-authored-by: David Foster &amp;lt;david@dafoster.net&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If I ever want to make such unreviewed or minimally-reviewed AI-drafted code public, I can use &lt;code&gt;git blame&lt;/code&gt; to easily identify which lines are principally AI-drafted, so that I can go back and review them carefully; I never publish AI-written code that I haven&amp;rsquo;t reviewed myself.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Tip: I use the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=SyedNisarUlHaq.git-spotlight&quot;&gt;Git Spotlight&lt;/a&gt; tool to quickly see which lines of code are written by AI (&lt;code&gt;C4&lt;/code&gt; = Claude Opus 4.6) or by me (&lt;code&gt;DF&lt;/code&gt; = David Foster). See below:&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;img alt=&quot;Visual 'git blame' view from the Git Spotlight VS Code extension&quot; src=&quot;/assets/2026/ai-attribution-in-git/git-blame-view-in-git-spotlight.png&quot; style=&quot;max-width: 100%&quot; /&gt;&lt;/p&gt;

&lt;h2&gt;Why the Co-authored-by pattern?&lt;/h2&gt;

&lt;p&gt;Claude Code introduced the convention of adding a &lt;code&gt;Co-Authored-By: Claude &amp;lt;noreply@anthropic.com&amp;gt;&lt;/code&gt; trailer to any AI-authored commits by telling the AI to use such trailers &lt;a href=&quot;https://github.com/Piebald-AI/claude-code-system-prompts/blob/5bb71ee182ec4005d8fad0ae18fc70a19da9572b/system-prompts/tool-description-bash-git-commit-and-pr-creation-instructions.md&quot;&gt;in its system prompt&lt;/a&gt;, much to the &lt;a href=&quot;https://github.com/anthropics/claude-code/issues/45137#issuecomment-4234095781&quot;&gt;annoyance&lt;/a&gt; of some users. GitHub recognizes that Co-Authored-By trailer and displays Claude as a co-author of the related commit.&lt;/p&gt;

&lt;p&gt;I think that kind of attribution is lightweight and makes sense.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2026/02/23/oops-i-wrote-a-database</id>
   <title>Oops, I wrote a database</title>
   <published>2026-02-23T00:00:00+00:00</published>
   <updated>2026-02-23T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2026/02/23/oops-i-wrote-a-database/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;blockquote&gt;&lt;p&gt;Never write your own database or filesystem. It&amp;rsquo;s way harder than you expect.&lt;br/&gt;
— some wise programmer&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Databases and filesystems are hard to write in part because they have very strong requirements around &lt;strong&gt;never losing data&lt;/strong&gt; (durability) even when unusual events happen such as unexpected process termination, hardware failure, out of disk space, or out of memory. I realized recently that Crystal - a program of mine for downloading websites - should strive to provide the same high reliability guarantees when saving websites to disk in its project format. And so began my ~3-week quest to shore up the ACID (atomicity, consistency, isolation, and durability) properties of how Crystal writes to its projects. Here are a few things I learned along the way.&lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;A Crystal project is an ACID-compliant storage system for holding downloaded website data: multiple-reader, single-writer.&lt;/p&gt;

&lt;p&gt;It contains a SQLite table of downloaded page &lt;strong&gt;revisions&lt;/strong&gt;, each row of which corresponds to an on-disk file with the revision&amp;rsquo;s content.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2026/oops-i-wrote-a-database/revision-table-to-files.svg&quot; alt=&quot;A project's revisions table, with a line connecting each table row to a file&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Adding a revision requires creating both a database row and file at the same time.&lt;/p&gt;

&lt;h2&gt;Strategy: Write file then rename to commit&lt;small&gt;, rather than (re)write in place&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s not safe to write a file directly to its final location because sudden process termination or disk disconnection could abort the write in the middle, leaving an incompletely written file in its final &amp;ldquo;committed&amp;rdquo; location.&lt;/p&gt;

&lt;p&gt;Instead it&amp;rsquo;s safer to write a file first to a temporary location on the same filesystem as its committed location. After the write is complete, move it to its final place.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2026/oops-i-wrote-a-database/file-write-and-replace.svg&quot; alt=&quot;An old revision file connected by line to multiple readers (👁 icons). A new revision file connected by line to one writer (✏️ icon). A wide &amp;quot;Replace&amp;quot; arrow leading from the new revision file to the old revision file.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If sudden process termination stops the write, when Crystal reopens the project it will delete the temporary file. Additionally Crystal will check whether the highest numbered revision row in the database is missing its corresponding revision file, and delete the incomplete revision row if so.&lt;/p&gt;

&lt;h2&gt;Strategy: Write file then replace to commit&lt;small&gt;, if the file may have concurrent readers&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;Crystal projects using the Pack16 format have a more complex challenge: Each revision row now corresponds to an entry in a zip file that can be shared by up to 16 revisions. Thus writing one revision may require altering a zip file containing a different revision that is being concurrently read.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2026/oops-i-wrote-a-database/revision-table-to-zip-entries.svg&quot; alt=&quot;A project's revisions table, with a line connecting each table row to an entry inside a zip file. There are many rows but only a few zip files, with each zip file connected to multiple rows.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Similar to the write+rename strategy, we can use a write+replace strategy: Write a new revision to a new zip file and then replace the old zip file. Existing readers of the old zip file will not be disrupted; they will still be able to read from the copy of the zip file that they opened even though it is no longer visible in the filesystem.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2026/oops-i-wrote-a-database/zip-file-write-and-replace.svg&quot; alt=&quot;An old zip file connected by line to multiple readers (👁 icons). A new zip file connected by line to one writer (✏️ icon). A wide &amp;quot;Replace&amp;quot; arrow leading from the new zip file to the old zip file.&quot; /&gt;&lt;/p&gt;

&lt;h2&gt;Windows-only: Move-aside a file before replacing it&lt;/h2&gt;

&lt;p&gt;On macOS and Linux the above strategy just works; it is possible to replace a file that is open for reading with a different file without doing anything special. However on Windows files are opened in an exclusive mode by default that prevents reading or writing the file while it is still open. &lt;strong&gt;You must &lt;em&gt;explicitly&lt;/em&gt; open a file with &lt;code&gt;FILE_SHARE_READ&lt;/code&gt;, &lt;code&gt;FILE_SHARE_WRITE&lt;/code&gt;, or &lt;code&gt;FILE_SHARE_DELETE&lt;/code&gt; modes on Windows if you want to allow concurrent readers, writers, or deleters.&lt;/strong&gt; Crystal defines its own &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/21bbf89d358d88336a8ba4e506a9681a2a62d83a/src/crystal/filesystem/local.py#L15-L92&quot;&gt;&lt;code&gt;open_nonexclusive&lt;/code&gt;&lt;/a&gt; function to get this same non-exclusive open behavior across all operating systems.&lt;/p&gt;

&lt;p&gt;However Windows presents another challenge: It does not allow you to &lt;em&gt;replace&lt;/em&gt; a file that is opened for reading even if it is opened with all of &lt;code&gt;FILE_SHARE_READ&lt;/code&gt;, &lt;code&gt;FILE_SHARE_WRITE&lt;/code&gt;, and &lt;code&gt;FILE_SHARE_DELETE&lt;/code&gt;, despite allowing you to &lt;em&gt;delete&lt;/em&gt; it or &lt;em&gt;rename&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;So on Windows, Crystal renames an old zip file to a transitional (but crash-durable) &amp;ldquo;moved-aside&amp;rdquo; location before renaming the new zip file to the original location of the old zip file. So the total process looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write new zip file to temporary location&lt;/li&gt;
&lt;li&gt;Move aside the old zip file to a moved-aside location

&lt;ul&gt;
&lt;li&gt;This is permitted even if the old zip file has readers, when opened with &lt;code&gt;FILE_SHARE_WRITE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Rename the new zip file to its permanent location, where the old zip file was&lt;/li&gt;
&lt;li&gt;Delete the old zip file in its moved-aside location

&lt;ul&gt;
&lt;li&gt;This is permitted even if the old zip file has readers, when opened with &lt;code&gt;FILE_SHARE_DELETE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;&lt;img src=&quot;/assets/2026/oops-i-wrote-a-database/windows-move-aside.svg&quot; alt=&quot;An old zip file connected by line to multiple readers (👁 icons). A &amp;quot;moved-aside&amp;quot; zip file. A new zip file connected by line to one writer (✏️ icon). A wide &amp;quot;2. Move Aside&amp;quot; arrow leading from the old zip file to the moved-aside zip file. A wide &amp;quot;3. Rename&amp;quot; arrow leading from the new zip file to the old zip file. A &amp;quot;4. Delete&amp;quot; box beside the moved-aside zip file.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The above (non-atomic) process introduces several complexities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ZeroWidthSpace;A. If &lt;strong&gt;a new concurrent reader&lt;/strong&gt; appears between steps 2 and 3, when the old zip file has been moved-aside but not yet replaced with a new zip file, the reader must know to look for the old zip file at the moved-aside location in addition to its normal location.&lt;/li&gt;
&lt;li&gt;B1. If &lt;strong&gt;sudden process termination&lt;/strong&gt; happens between steps 2 and 3, some kind of repair process after reopening the project must move the old zip file from its moved-aside location back to its normal location.&lt;/li&gt;
&lt;li&gt;B2. If &lt;strong&gt;sudden process termination&lt;/strong&gt; happens between steps 3 and 4, the old zip file in the moved-aside location should be deleted.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In case B1, Crystal performs the repair at read time, when an entry from the zip file is first read after reopening the project.&lt;/p&gt;

&lt;h2&gt;Read Repair&lt;small&gt;: A time to clean up incomplete operations&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;When Crystal performs a read on a Pack16 project, looks for a zip file corresponding to a revision, and does not find it, it will then look for a moved-aside zip file that was left behind during scenario B1 above. If it finds such a moved-aside zip file it will &lt;em&gt;repair&lt;/em&gt; it by moving it back to its normal location.&lt;/p&gt;

&lt;p&gt;Note that this kind of repair is itself a kind of &lt;strong&gt;write&lt;/strong&gt; which might happen during a high-level &lt;strong&gt;read&lt;/strong&gt; operation. Since Crystal allows &lt;em&gt;concurrent reads&lt;/em&gt;, the possibility of a repair happening during a read means that &lt;em&gt;concurrent writes&lt;/em&gt; are now possible too&amp;hellip; Yikes.&lt;/p&gt;

&lt;p&gt;Concurrent writes to the same file are unsafe by default but can be made safe with &lt;strong&gt;mutual exclusion&lt;/strong&gt;. Crystal maintains an in-memory mutex lock for each file it is in the middle of repairing to prevent concurrent writes from corrupting the project.&lt;/p&gt;

&lt;h2&gt;Zooming Out: The Big Picture&lt;/h2&gt;

&lt;p&gt;I expected this work to take 1–1.5 weeks. It took about three. Most of the overrun came from a cascade of complications I didn&amp;rsquo;t see coming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows opens files exclusively by default, so even allowing &lt;strong&gt;concurrent readers&lt;/strong&gt; required &lt;code&gt;FILE_SHARE_READ&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Windows then refused to &lt;em&gt;replace&lt;/em&gt; a file that was still open for reading — even with all three share modes set — so &lt;strong&gt;writes&lt;/strong&gt; required the move-aside dance and &lt;code&gt;FILE_SHARE_WRITE&lt;/code&gt; / &lt;code&gt;FILE_SHARE_DELETE&lt;/code&gt; on the reader side.&lt;/li&gt;
&lt;li&gt;The move-aside dance introduced two new &lt;strong&gt;crash-recovery&lt;/strong&gt; cases (B1 and B2), which became read-repair.&lt;/li&gt;
&lt;li&gt;Read-repair quietly turned reads into potential writes, which forced in-memory &lt;strong&gt;per-revision locks&lt;/strong&gt; to keep the multiple-reader/single-writer contract honest.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Each layer was reasonable on its own; the surprise was how much each one cost in aggregate.&lt;/p&gt;

&lt;p&gt;Of the four ACID properties, &lt;strong&gt;atomicity&lt;/strong&gt; and &lt;strong&gt;durability&lt;/strong&gt; drove essentially all of this work. &lt;strong&gt;Consistency&lt;/strong&gt; was largely a freebie given the architecture: the database lives in one place, only one process ever opens a project, and that process has at most one writer. &lt;strong&gt;Isolation&lt;/strong&gt; was similarly cheap given the single-writer rule and the absence of in-place rewrites — with the wrinkle that read-repair turned a &amp;ldquo;read&amp;rdquo; into a {read + limited write}, requiring introducing per-revision locks.&lt;/p&gt;

&lt;p&gt;It was a fun exercise in polishing one aspect of Crystal to a high standard. But I must say the caution around hand-rolling your own storage code is well earned: you may very well double or triple the time you expect it to take. 🙂&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;I can&amp;rsquo;t find a specific original person who said &amp;ldquo;Never write your own database or filesystem&amp;rdquo;. The closest discussion I was able to locate comes from &lt;a href=&quot;https://terrycrowley.medium.com/never-write-your-own-database-736f704c780&quot;&gt;Never Write Your Own Database&lt;/a&gt;. So perhaps this specific quote just comes from me now 🙂&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2025/08/20/issue-counts-always-go-up</id>
   <title>Issue counts always go up</title>
   <published>2025-08-20T00:00:00+00:00</published>
   <updated>2025-08-20T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2025/08/20/issue-counts-always-go-up/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;a href=&quot;/assets/2025/issue-counts-always-go-up/issue-asteroids.jpg&quot;&gt;&lt;img id=&quot;issue-asteroids&quot; src=&quot;/assets/2025/issue-counts-always-go-up/issue-asteroids.jpg&quot; alt=&quot;A spaceship labelled 'Me' firing shots at a big asteroid, labelled '-1 Issue'. The big asteroid is exploding into 3 smaller asteroids, each labelled '+1 Issue'.&quot; data-credits=&quot;Gemini 2.0 Flash Preview Image Generation, prompted and manually edited in Acorn by David Foster&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve noticed that the GitHub issue count on my software project Crystal always seems to go up, even though I&amp;rsquo;m the only one who ever files issues (for now) and even though I&amp;rsquo;m actually completing issues occasionally.&lt;/p&gt;

&lt;p&gt;I think I&amp;rsquo;ve figured out why: Often when I complete an issue, I only complete the first 80% of the issue which is most valuable to me and file smaller issues for the remaining 20% that is left. So I end up with 1 big issue completed and 2+ smaller issues created. Net effect is that &lt;strong&gt;more issues are opened than closed even though the missing functionality goes down&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s like a game of asteroids, where blowing up the big asteroid just creates a bunch of smaller asteroids.&lt;/p&gt;

&lt;p&gt;So I can&amp;rsquo;t easily see progress by watching the &lt;em&gt;issue count&lt;/em&gt; go down. Instead I need to think of a way to measure the amount of &lt;em&gt;missing functionality&lt;/em&gt; so that I can see that go down instead and feel good about completing issues. 🙂&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2025/issue-counts-always-go-up/measuring-bugs.jpg&quot; style=&quot;max-width: 100%; max-height: 300px; display: block; margin: 0 auto;&quot; alt=&quot;Professor holding a measuring tool over a set of small bugs arranged on a table.&quot; data-credits=&quot;Gemini 2.0 Flash Preview Image Generation, prompted by David Foster&quot; /&gt;&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2025/07/22/designing-software-in-the-large</id>
   <title>Designing Software in the Large</title>
   <published>2025-07-22T00:00:00+00:00</published>
   <updated>2025-07-22T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2025/07/22/designing-software-in-the-large/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Philosophy-Software-Design-2nd/dp/173210221X/&quot;&gt;A Philosophy of Software Design&lt;/a&gt; is my favorite book I&amp;rsquo;ve read to date about designing large long-lived maintainable software programs. Here&amp;rsquo;s what I learned:&lt;/p&gt;

&lt;h2&gt;Complexity&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Complexity&lt;/strong&gt; is anything related to the structure of a software system that makes it hard to understand &amp;amp; modify the system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Symptoms of complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Change Amplification&lt;/strong&gt; - A seemingly simple change requires code modifications in many different places.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Cognitive Load&lt;/strong&gt; - High amount of information a developer needs to know to complete a task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unknown Unknowns&lt;/strong&gt; - When it is not obvious which pieces of code must be modified to complete a task, or what information a developer must have to carry out the task successfully.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Causes of complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dependencies&lt;/strong&gt; - A dependency exists when a given piece of code cannot be understood and modified in isolation; the code relates in some way to other code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Obscurity&lt;/strong&gt; - Obscurity occurs when important information is not obvious.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/section0.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/section0.svg&quot; style=&quot;max-width: 100%; max-height: 268px;&quot; alt=&quot;A concept map diagram showing symptoms and causes of complexity, and how they related to each other&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To keep a software system maintainable, you must strive to keep the complexity of the system low as you &amp;amp; others make changes to it.&lt;/p&gt;

&lt;h3&gt;The big picture&lt;/h3&gt;

&lt;p&gt;Concepts related to complexity, which the remaining sections of this article will zoom in on:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/section2.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/section2.svg&quot; style=&quot;max-width: 100%; border: 4px solid lightgray; border-radius: 12px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Dependencies: A Cause of Complexity&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;dependency&lt;/strong&gt; exists when a given piece of code cannot be understood in isolation; the code relates in some way to other code. Numerous and strong dependencies between modules of a system make it difficult to change one module without changing others (Change Amplification) and make it difficult to understand modules in isolation (High Cognitive Load).&lt;/p&gt;

&lt;p&gt;Key contributors to dependency-complexity are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Duplication&lt;/strong&gt; - Duplication occurs when the same knowledge is used in multiple places. This can be direct repetition of the same piece of code appearing in multiple places. Or it can be more subtle, such as multiple classes understanding the details of the same file format or network protocol.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exceptions&lt;/strong&gt; - An exception is a particularly complex element of an interface which can propagate not just from a method to its direct caller but also to higher level callers (and their interfaces).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inheritance&lt;/strong&gt; - Implementation inheritance in object-oriented systems creates dependencies between the parent class and each of its subclasses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temporal Decomposition&lt;/strong&gt; - A system exhibits temporal decomposition when its structure corresponds to the time order in which operations will occur.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The opposite of dependency-complexity is &lt;strong&gt;cohesive code&lt;/strong&gt;, created primarily by focusing on designing &lt;strong&gt;deep modules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/section1.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/section1.svg&quot; style=&quot;max-width: 100%; max-height: 550px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep modules&lt;/strong&gt; allow a lot of functionality to be accessed through a small interface:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/deep-and-shallow-modules.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/deep-and-shallow-modules.svg&quot; style=&quot;max-width: 100%; max-height: 325px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keeping module interfaces small lowers the number and strength of dependencies between modules, resulting in lower overall system complexity:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2017/abstraction-and-encapsulation/complexity_comparison.png&quot;&gt;&lt;img alt=&quot;Complexity with and without abstractions&quot; src=&quot;/assets/2017/abstraction-and-encapsulation/complexity_comparison.png&quot; style=&quot;max-width: 100%; max-height: 450px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chapters 4-9 of the book are related to techniques for forming deeper modules. My article &lt;a href=&quot;/articles/2017/03/25/how-to-design-large-programs-with-abstraction-and-encapsulation/&quot;&gt;How to Design Large Programs with Abstraction and Encapsulation&lt;/a&gt; also discusses deep modules in the context of encapsulation &amp;amp; abstraction.&lt;/p&gt;

&lt;h2&gt;Obscurity: A Cause of Complexity&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Obscurity&lt;/strong&gt; occurs when important information is not obvious.&lt;/p&gt;

&lt;p&gt;Obscurity creates Unknown Unknowns and contributes to High Cognitive Load:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/section3.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/section3.svg&quot; style=&quot;max-width: 100%; max-height: 450px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key contributors to obscurity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vague Names&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inconsistency&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inadequate Documentation&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Smaller contributors to obscurity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;indirection via &lt;strong&gt;listeners&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;indirection via &lt;strong&gt;polymorphism&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;using &lt;strong&gt;generic containers to hold structured data&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The opposite of obscurity is &lt;strong&gt;obvious code&lt;/strong&gt;. Obvious code&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uses &lt;strong&gt;precise names&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;is &lt;strong&gt;consistent&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;is &lt;strong&gt;well-documented&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;makes good use of &lt;strong&gt;whitespace&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/section4.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/section4.svg&quot; style=&quot;max-width: 100%; max-height: 400px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many techniques for creating &lt;strong&gt;consistency&lt;/strong&gt; in code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent use of names&lt;/strong&gt;, &lt;strong&gt;consistent code style&lt;/strong&gt;, and &lt;strong&gt;consistent implementation patterns&lt;/strong&gt; are hallmarks of consistency in general.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tools such as &lt;strong&gt;autoformatters&lt;/strong&gt;, &lt;strong&gt;linters&lt;/strong&gt;, and &lt;strong&gt;automated consistency tests&lt;/strong&gt; are great for enforcing consistency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; of conventions can be captured in &lt;strong&gt;coding style guides&lt;/strong&gt; and through references to documented &lt;strong&gt;design patterns&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a href=&quot;/assets/2025/designing-software-in-the-large/section5.svg&quot;&gt;&lt;img src=&quot;/assets/2025/designing-software-in-the-large/section5.svg&quot; style=&quot;max-width: 100%; max-height: 400px;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Strategic vs. Tactical Mindset&lt;/h2&gt;

&lt;p&gt;&lt;img id=&quot;tactical-tornado-img&quot; src=&quot;/assets/2025/designing-software-in-the-large/tactical-tornado.svg&quot; style=&quot;float: right; margin-left: 0.5em; margin-bottom: 0.5em; max-width: 150px;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Complexity accumulates naturally in a software system if left unchecked.&lt;/p&gt;

&lt;p&gt;And once complexity has accumulated it is hard to eliminate.&lt;/p&gt;

&lt;p&gt;Therefore the book recommends taking a &amp;ldquo;zero-tolerance&amp;rdquo; stance toward the incremental introduction of complexity.&lt;/p&gt;

&lt;p&gt;Specifically, it advocates taking a &lt;strong&gt;strategic approach&lt;/strong&gt; to programming tasks, where you intentionally invest time to produce clean designs and fix problems, in addition to getting new features working.&lt;/p&gt;

&lt;p&gt;Many programmers, by contrast, take a purely &lt;strong&gt;tactical approach&lt;/strong&gt; that focuses &lt;em&gt;only&lt;/em&gt; on getting new features working, disregarding the long-term costs of adding incremental complexity and other forms of cutting corners.&lt;/p&gt;

&lt;h2&gt;Takeaway&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Working code (alone) is not enough.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To keep a software system maintainable, you must strive to keep the complexity of the system low as you &amp;amp; others make changes to it.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2025/03/16/the-trouble-with-the-symbol-type</id>
   <title>The trouble with the Symbol type</title>
   <published>2025-03-16T00:00:00+00:00</published>
   <updated>2025-03-16T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2025/03/16/the-trouble-with-the-symbol-type/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;There are a few languages that offer &lt;strong&gt;a symbol type&lt;/strong&gt;, notably JavaScript, Ruby, Lisp, and Erlang. A symbol is similar to a string but guarantees that only one copy of the symbol exists with the same value. In JavaScript you can create a symbol with the code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;Symbol.for('hello')
// Symbol(hello)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Symbols can be compared with each other for equality very quickly&lt;/strong&gt; because only the object references need to be compared; the values do not need to be compared. This high speed of comparison is the main advantage that symbols offer over strings.&lt;/p&gt;

&lt;p&gt;However:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every symbol that is created must be added to a global registry of all symbols to ensure that it is unique. Since all symbols live in this global registry and there is no way to remove a symbol from the registry, &lt;strong&gt;a symbol may never be garbage collected&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Because symbols live forever, &lt;strong&gt;it is unwise to create a symbol from an arbitrary (unknown) string&lt;/strong&gt;, because doing so repeatedly will fill up memory with immortal symbol objects.&lt;/li&gt;
&lt;li&gt;Similarly it is &lt;strong&gt;unwise to deserialize a symbol&lt;/strong&gt; from (untrusted) input because - again - doing so repeatedly will fill up memory with immortal symbol objects.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To avoid the above problems &lt;strong&gt;I generally prefer using strings instead of symbols&lt;/strong&gt;. Strings can be freely serialized/deserialized safely and they can be garbage collected. Although strings cannot be compared with each other as fast as symbols can, they still compare very fast, especially for short strings.&lt;/p&gt;

&lt;h2&gt;Related: Interned Strings&lt;/h2&gt;

&lt;p&gt;Some languages don&amp;rsquo;t have a symbol type but do have &lt;strong&gt;a string type that can be &amp;ldquo;interned&amp;rdquo;&lt;/strong&gt;, notably Java and Python. When a string is interned it is added to the global registry of all interned strings (if it wasn&amp;rsquo;t there already) and the copy from the registry is returned.&lt;/p&gt;

&lt;p&gt;Java&amp;rsquo;s interned strings are immortal and are never garbage collected.&lt;/p&gt;

&lt;p&gt;Python&amp;rsquo;s interned strings are NOT immortal and will be garbage collected if no references to an interned string exist outside of the global registry.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2025/03/13/dump-traceback-on-print</id>
   <title>Dumping a traceback when an error message is printed</title>
   <published>2025-03-13T00:00:00+00:00</published>
   <updated>2025-03-13T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2025/03/13/dump-traceback-on-print/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;When a program I&amp;rsquo;m debugging prints something unexpected like an error message, I can usually search for a fragment of the message in the program&amp;rsquo;s code to figure out why it was printed.&lt;/p&gt;

&lt;p&gt;However sometimes I&amp;rsquo;m not able to locate the error message in the code at all! In that case one big hammer I have for isolating the offending code is to alter &lt;code&gt;print()&lt;/code&gt;, &lt;code&gt;sys.stdout.write()&lt;/code&gt;, and &lt;code&gt;sys.stderr.write()&lt;/code&gt; to dump a traceback whenever a fragment of the error message is about to be printed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;altair (https://github.com/vega/altair)
+ &amp;lt;type_comment&amp;gt;:1: SyntaxWarning: invalid escape sequence '\('
+ 
+ *** Keyword 'SyntaxWarning' printed at:
+   File &quot;/new_mypy/bin/mypy&quot;, line 10, in &amp;lt;module&amp;gt;
+     sys.exit(console_entry())
+   File &quot;/new_mypy/mypy/__main__.py&quot;, line 15, in console_entry
+     main()
+   File &quot;/new_mypy/mypy/main.py&quot;, line 156, in main
+     res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+   File &quot;/new_mypy/mypy/main.py&quot;, line 240, in run_build
+     res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
+   File &quot;/new_mypy/mypy/build.py&quot;, line 191, in build
+     result = _build(
+   File &quot;/new_mypy/mypy/build.py&quot;, line 267, in _build
+     graph = dispatch(sources, manager, stdout)
+   File &quot;/new_mypy/mypy/build.py&quot;, line 2937, in dispatch
+     process_graph(graph, manager)
+   File &quot;/new_mypy/mypy/build.py&quot;, line 3335, in process_graph
+     process_stale_scc(graph, scc, manager)
+   File &quot;/new_mypy/mypy/build.py&quot;, line 3430, in process_stale_scc
+     mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
+   File &quot;/new_mypy/mypy/semanal_main.py&quot;, line 94, in semantic_analysis_for_scc
+     process_functions(graph, scc, patches)
+   File &quot;/new_mypy/mypy/semanal_main.py&quot;, line 252, in process_functions
+     process_top_level_function(
+   File &quot;/new_mypy/mypy/semanal_main.py&quot;, line 291, in process_top_level_function
+     deferred, incomplete, progress = semantic_analyze_target(
+   File &quot;/new_mypy/mypy/semanal_main.py&quot;, line 351, in semantic_analyze_target
+     analyzer.refresh_partial(
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 668, in refresh_partial
+     self.accept(node)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 7320, in accept
+     node.accept(self)
+   File &quot;/new_mypy/mypy/nodes.py&quot;, line 818, in accept
+     return visitor.visit_func_def(self)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 926, in visit_func_def
+     self.analyze_func_def(defn)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 1007, in analyze_func_def
+     self.analyze_function_body(defn)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 1601, in analyze_function_body
+     defn.body.accept(self)
+   File &quot;/new_mypy/mypy/nodes.py&quot;, line 1285, in accept
+     return visitor.visit_block(self)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 5272, in visit_block
+     self.accept(s)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 7320, in accept
+     node.accept(self)
+   File &quot;/new_mypy/mypy/nodes.py&quot;, line 1641, in accept
+     return visitor.visit_with_stmt(self)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 5424, in visit_with_stmt
+     e.accept(self)
+   File &quot;/new_mypy/mypy/nodes.py&quot;, line 1997, in accept
+     return visitor.visit_call_expr(self)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 5837, in visit_call_expr
+     self.try_parse_as_type_expression(a)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 7719, in try_parse_as_type_expression
+     t = self.expr_to_analyzed_type(maybe_type_expr)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 7355, in expr_to_analyzed_type
+     typ = self.expr_to_unanalyzed_type(expr)
+   File &quot;/new_mypy/mypy/semanal.py&quot;, line 7418, in expr_to_unanalyzed_type
+     return expr_to_unanalyzed_type(
+   File &quot;/new_mypy/mypy/exprtotype.py&quot;, line 202, in expr_to_unanalyzed_type
+     return parse_type_string(expr.value, &quot;builtins.str&quot;, expr.line, expr.column)
+   File &quot;/new_mypy/mypy/fastparse.py&quot;, line 327, in parse_type_string
+     _, node = parse_type_comment(f&quot;({expr_string})&quot;, line=line, column=column, errors=None)
+   File &quot;/new_mypy/mypy/fastparse.py&quot;, line 288, in parse_type_comment
+     typ = ast3_parse(type_comment, &quot;&amp;lt;type_comment&amp;gt;&quot;, &quot;eval&quot;)
+   File &quot;/new_mypy/mypy/fastparse.py&quot;, line 142, in ast3_parse
+     return ast3.parse(
+   File &quot;/usr/lib/python3.12/ast.py&quot;, line 52, in parse
+     return compile(source, filename, mode, flags,
+   File &quot;/usr/lib/python3.12/warnings.py&quot;, line 113, in _showwarnmsg
+     _showwarnmsg_impl(msg)
+   File &quot;/usr/lib/python3.12/warnings.py&quot;, line 30, in _showwarnmsg_impl
+     file.write(text)
+   File &quot;/new_mypy/mypy/main.py&quot;, line 98, in write
+     traceback.print_stack(file=self.wrapped)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that the dumped traceback points directly at the offending code.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s Python code which monkeypatches prints to dump a traceback whenever a particular substring is printed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import sys
import traceback

def print_traceback_whenever_printed_line_contains(needle: str) -&amp;gt; None:
    &quot;&quot;&quot;
    Replaces sys.stdout with a wrapper that inspects each write. If the output
    contains 'needle', a traceback is printed to the original sys.stdout.
    The monkeypatch remains in place after this function returns.
    &quot;&quot;&quot;
    class PatchedStdStream:
        def __init__(self, wrapped):
            self.wrapped = wrapped

        def write(self, text: str) -&amp;gt; None:
            # Write text to the original stdout
            self.wrapped.write(text)

            # Check if 'needle' is in the text being written
            if needle in text:
                # Print a traceback to the original stdout
                self.wrapped.write(f'\n*** Keyword {needle!r} printed at:\n')
                traceback.print_stack(file=self.wrapped)

        def __getattr__(self, name: str):
            &quot;&quot;&quot;
            Forward all other attributes (e.g., flush, fileno, isatty, etc.)
            to the original stdout.
            &quot;&quot;&quot;
            return getattr(self.wrapped, name)

    sys.stdout = PatchedStdStream(sys.stdout)
    sys.stderr = PatchedStdStream(sys.stderr)

if __name__ == &quot;__main__&quot;:
    # Activate the patch to watch for &quot;ERROR&quot; in any output
    print_traceback_whenever_printed_line_contains(&quot;ERROR&quot;)

    print(&quot;Everything is normal here...&quot;)
    print(&quot;Some random text with ERROR inside it!&quot;)
    print(&quot;Continuing after error message...&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2024/08/18/effective-code-reviews</id>
   <title>Effective Code Reviews</title>
   <published>2024-08-18T00:00:00+00:00</published>
   <updated>2024-08-18T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2024/08/18/effective-code-reviews/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Software engineering research has identified&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; some techniques and rules of thumb for making code reviews more effective at identifying defects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Limit code reviews to &lt;strong&gt;1 hour or less&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;After 60-90 minutes into a code review the ability to find further defects drops off dramatically due to focus fatigue.&lt;/li&gt;
&lt;li&gt;If a code review in progress is dragging on past 1 hour, consider taking a break and continuing the remainder later in a &amp;ldquo;part 2&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limit code reviews to &lt;strong&gt;400 lines of code or less&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Code reviews performed faster than 400-500 lines of code per hour show a dramatic drop in density of detected defects.&lt;/li&gt;
&lt;li&gt;Combining that result with the earlier result that reviews lasting longer than 1 hour are problematic, we can conclude that no more than 400 lines of code should be reviewed in the same session.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identify the most complex/risky/controversial changes to review first&lt;/strong&gt; when there is the least focus fatigue.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Link to related &amp;ldquo;context&amp;rdquo; (i.e. files, documentation, classes, etc)&lt;/strong&gt; alongside the immediate changes of a code review, for a 15-30% increase in defect detection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-review changes before posting them for external review&lt;/strong&gt;, because 50% of defects can be found in a self-review at half the time cost of an external review.&lt;/li&gt;
&lt;li&gt;An individual code review should be either asynchronous or synchronous but not both.

&lt;ul&gt;
&lt;li&gt;For a code review posted asynchronously, there is little gain in following up with an additional full synchronous review: Only an additional 4% of defects are likely to be found.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;All results in this article originate from the &amp;ldquo;Modern Code Review&amp;rdquo; chapter of &lt;a href=&quot;https://www.amazon.com/Making-Software-Really-Works-Believe/dp/0596808321&quot;&gt;&amp;ldquo;Making Software: What Really Works, and Why We Believe It&amp;rdquo;&lt;/a&gt; by Jason Cohen, unless otherwise specified.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;This result comes from another source which I have since forgotten.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2024/06/16/pycon-us-2024-highlights</id>
   <title>PyCon US 2024 Highlights</title>
   <published>2024-06-16T00:00:00+00:00</published>
   <updated>2024-06-16T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2024/06/16/pycon-us-2024-highlights/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I was happy to be able to attend &lt;a href=&quot;https://us.pycon.org/2024/&quot;&gt;PyCon US 2024&lt;/a&gt; this past year, a prominent conference for the Python programming language. I got to meet in person a number of folks I&amp;rsquo;ve interacted with online, from the Python Typing community and elsewhere.&lt;/p&gt;

&lt;h2&gt;Favorite Talks&lt;/h2&gt;

&lt;p&gt;I particularly liked the following talks, which I&amp;rsquo;ve organized by topic.&lt;/p&gt;

&lt;p&gt;Most video links below are to the Hublio platform, which only conference attendees can access. Unfortunately the talk recordings have not yet been shared more widely on YouTube.&lt;/p&gt;

&lt;h3&gt;Performance&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unlocking the Parallel Universe: Subinterpreters and Free-Threading in Python 3.13&lt;/strong&gt; - Anthony Shaw

&lt;ul&gt;
&lt;li&gt;Shows many ways to run Python programs in parallel: in different processes, different interpreters, and different threads. There are tradeoffs with each strategy.&lt;/li&gt;
&lt;li&gt;Insight: &amp;ldquo;Subinterpreters will be a better solution than Multiprocessing for long-running workers.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Insight: Free threading is a good solution for workers that need the fastest data exchange between workers. But free threading is difficult to program correctly, without race conditions.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234270&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overcoming GIL with subinterpreters and immutability&lt;/strong&gt; - Yury Selivanov

&lt;ul&gt;
&lt;li&gt;Introduces &lt;a href=&quot;https://github.com/edgedb/memhive&quot;&gt;memhive&lt;/a&gt;, a new library for safely sharing state across multiple Python interpreters in the same process, by providing an immutable/persistent map structure (HAMT) that can be efficiently updated and shared between interpreters&lt;/li&gt;
&lt;li&gt;Insight: Subinterpreters are a better solution than Multiprocessing for workers that need to share state - such as a cache - between workers, because subinterpreter workers share memory. Subinterpreters are easier to program than free threading.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234227&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Debugging&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Profiling at the speed of light&lt;/strong&gt; - Pablo Galindo Salgado

&lt;ul&gt;
&lt;li&gt;Showed how to use the &lt;a href=&quot;https://perf.wiki.kernel.org/index.php/Main_Page&quot;&gt;perf&lt;/a&gt; tool on a Python 3.12 and 3.13 process to look at low-level performance metrics like CPU-level and instruction-level counters.&lt;/li&gt;
&lt;li&gt;Showed how to make flame graphs to see where a mixed Python+C program is spending its time visually.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234204&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rewind: Python Time-Travel Debugger&lt;/strong&gt; - Toby Ho

&lt;ul&gt;
&lt;li&gt;Showed &lt;a href=&quot;https://github.com/airportyh/time-traveling-debugger&quot;&gt;pyrewind&lt;/a&gt;, a time-travel reverse-debugger for Python. Looks like a promising tool for pure Python code.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s unclear whether the tool supports &lt;a href=&quot;https://github.com/airportyh/time-traveling-debugger/issues/47&quot;&gt;debugging in the presence of C extensions&lt;/a&gt;, which may have side effects that the debugger does not track.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234187&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;API Design&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Design of Everyday APIs&lt;/strong&gt; - Lynn Root

&lt;ul&gt;
&lt;li&gt;Outlined several principles for improving the design of APIs.&lt;/li&gt;
&lt;li&gt;Gives &amp;ldquo;before&amp;rdquo; and &amp;ldquo;after&amp;rdquo; examples when applying these principles
to an example API.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234189&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.roguelynn.com/talks/everyday-apis/&quot;&gt;🎞 Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;AI&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keynote&lt;/strong&gt; - Simon Willison

&lt;ul&gt;
&lt;li&gt;Great talk about AI and Machine Learning. Many interesting quotes from this presentation.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;You shouldn&amp;rsquo;t need a CS degree to automate stuff with a computer&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234277&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lies, damned lies and large language models&lt;/strong&gt; - Jodie Burchell

&lt;ul&gt;
&lt;li&gt;Describes different types of hallucinations that Large Language Models (LLMs) can experience.&lt;/li&gt;
&lt;li&gt;Shows how to measure how much a particular model hallucinates.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234236&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Typing System&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theory of Type Hints, Revisited&lt;/strong&gt; - Carl Meyer

&lt;ul&gt;
&lt;li&gt;Covers in-progress efforts to increase the formality of the underlying theory behind Python&amp;rsquo;s type system, especially with respect to what the &lt;code&gt;Any&lt;/code&gt; type means. These efforts have been partially motivated by ongoing work (for over a year) to attempt to introduce an &lt;code&gt;Intersection&lt;/code&gt; type into Python&amp;rsquo;s typing system.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discuss.python.org/t/typing-summit-at-pycon-us-2024-17-may-2024/44421&quot;&gt;📽 Video pending&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeForm: Type Hint for Type Expressions&lt;/strong&gt; - David Foster

&lt;ul&gt;
&lt;li&gt;Covers &lt;code&gt;TypeForm&lt;/code&gt;, an in-progress Python type system feature for spelling a &amp;ldquo;type expression object&amp;rdquo; at runtime. This was my own talk. More details in PEP 747.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GOSG2qXMdcM&quot;&gt;📽 Video (YouTube)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Fun&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build in-browser 3D experiences with WebGL and PyScript&lt;/strong&gt; - Łukasz Langa

&lt;ul&gt;
&lt;li&gt;Showed how to use Python to draw 3D graphics in the browser with WebGL.&lt;/li&gt;
&lt;li&gt;Showed how to take data from a data processing library in Python and directly visualize it by talking to JavaScript visualization libraries.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234214&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connecting Old to New with CircuitPython: Retrocomputer input devices on modern PCs&lt;/strong&gt; - Jeff Epler

&lt;ul&gt;
&lt;li&gt;Shows how to use Python to build connectors to old keyboards, mice, and other hardware devices.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://events.hubilo.com/pycon-us-2024/session/234265&quot;&gt;📽 Video (Hublio)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2024/03/24/redis-relicensing-why-is-this-a-problem</id>
   <title>Redis relicensing: Why is this a problem?</title>
   <published>2024-03-24T00:00:00+00:00</published>
   <updated>2024-03-24T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2024/03/24/redis-relicensing-why-is-this-a-problem/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I find the fire &amp;amp; heat around &lt;a href=&quot;https://redis.com/blog/redis-adopts-dual-source-available-licensing/&quot;&gt;Redis changing licensing&lt;/a&gt; surprising. Maintaining Redis takes effort which cannot be free in a sustainable fashion.&lt;/p&gt;

&lt;p&gt;Consider &lt;a href=&quot;https://andrewkelley.me/post/redis-renamed-to-redict.html&quot;&gt;this post&lt;/a&gt; which complains Redis isn&amp;rsquo;t &amp;ldquo;uphold[ing] the ideals of Free and Open Source Software&amp;rdquo;, as if it was created as a vehicle to evangelize the FSF and OSI missions. But it was not, it was created to be &lt;em&gt;useful&lt;/em&gt;, as a data structure server.&lt;/p&gt;

&lt;p&gt;I also disagree with that post&amp;rsquo;s assertion that Redis contributions would have been withheld if it started with a different license. I expect contributions would come from existing users of Redis who wanted new features themselves and were willing to sponsor the related effort, regardless of the license in use.&lt;/p&gt;

&lt;p&gt;Certainly if Redis has started under its new license and I was using Redis on Azure - which Microsoft has already bought a commercial license for - then I wouldn&amp;rsquo;t care that Redis was licensed under the SSPL.&lt;/p&gt;

&lt;p&gt;Frankly &lt;strong&gt;I think it would be a win for software sustainability if there was a trend of new software projects being offered under source-available licenses&lt;/strong&gt; requiring large cloud providers like AWS, Azure, and GCP to give back financially to the core maintainers.&lt;/p&gt;

&lt;p&gt;I plan to be announcing a project of my own soon under a source-available license restricting unlicensed commercial use. I&amp;rsquo;ve already put several years of effort into this project. No way in hell do I want to &lt;a href=&quot;https://youtu.be/XZ3w_jec1v8?si=tUHKi3BVzqwTzyIS&amp;amp;t=1695&quot;&gt;&amp;ldquo;get Jeff'ed&amp;rdquo;&lt;/a&gt;, with someone else selling what I&amp;rsquo;ve put so much of my own effort into creating without giving anything back.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2024/02/28/bulkheads-a-pattern-for-handling-unexpected-errors-in-software</id>
   <title>Bulkheads: A pattern for handling unexpected errors in software</title>
   <published>2024-02-28T00:00:00+00:00</published>
   <updated>2024-02-28T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2024/02/28/bulkheads-a-pattern-for-handling-unexpected-errors-in-software/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;img class=&quot;img-box-right img-350&quot; alt=&quot;Ship with bulkheads&quot; src=&quot;/assets/2024/bulkheads-a-pattern-for-handling-unexpected-errors-in-software/bulkheads-software.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some seafaring ships divide their body into multiple watertight compartments, so that if one compartment becomes flooded the rest of the ship will remain floodfree and intact. I got the idea of using a similar pattern of &amp;ldquo;bulkheads&amp;rdquo; in software to &lt;strong&gt;limit the damage caused by an unhandled &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/essential/exceptions/definition.html&quot;&gt;exception&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Normally an unhandled exception will cause its thread to print diagnostic information to the console and then stop. This is an acceptable error-handling strategy for many command-line programs, but it is &lt;em&gt;not&lt;/em&gt; a good error-handling strategy for a graphical program where the console is invisible.&lt;/p&gt;

&lt;h2&gt;Goals&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve been working on a graphical program where &lt;strong&gt;I want &lt;em&gt;all&lt;/em&gt; exceptions and errors to be reported to the user&lt;/strong&gt; in some way, rather than failing silently and presenting an unresponsive user interface when something goes wrong.&lt;/p&gt;

&lt;p&gt;Additionally, there are certain critical sections of the program where an unhandled exception could leave a nearby data structure in an invalid state, causing subsequent operations on that structure to fail and/or propagate the corruption to other parts of the program state. &lt;strong&gt;It would be better if an unhandled exception occurring in a critical section marked any affected data structures as corrupt, such that further operations attempting to access those structures would refuse to run.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Bulkheads Pattern&lt;/strong&gt; can be used to meet both of those goals:&lt;/p&gt;

&lt;h2&gt;How it Works&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve implemented a family of &lt;code&gt;@capture_crashes_to...&lt;/code&gt; function decorators in Python which mark a critical section of code and define which &lt;code&gt;Bulkhead&lt;/code&gt; the critical section is related to.&lt;/p&gt;

&lt;p&gt;Any exception raised in the critical section which bubbles up to the decorator will be caught at the last moment and set as the &lt;code&gt;crash_reason&lt;/code&gt; for the associated bulkhead.&lt;/p&gt;

&lt;p&gt;If a function calls into a critical section marked with &lt;code&gt;@capture_crashes_to...&lt;/code&gt; whose bulkhead has been marked as crashed, the critical section will refuse to run and will instead return to the caller immediately, possibly returning a default value.&lt;/p&gt;

&lt;h2&gt;Example&lt;/h2&gt;

&lt;p&gt;Below, the &lt;code&gt;child_task_did_complete&lt;/code&gt; listener method is marked with &lt;code&gt;@capture_crashes_to_self&lt;/code&gt;, so any unexpected exception raised inside the listener won&amp;rsquo;t escape and crash the thread which called the listener. Instead the exception will be stored in the Task&amp;rsquo;s &lt;code&gt;crash_reason&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;class Task(Bulkhead):
    crash_reason: Optional[BaseException] = None

class DownloadResourceTask(Task):
    @capture_crashes_to_self
    def child_task_did_complete(self, task: Task) -&amp;gt; None:
        if task is self._download_body_task:
            ...
        elif task is self._parse_links_task:
            links = self._parse_links_task.future.result()
            embedded_resources = [
                Resource(
                    self._resource.project,
                    urljoin(self._resource.url, link.relative_url))
                for link in links if not link.embedded
            ]
            for resource in embedded_resources:
                self.append_child(resource.create_download_task(...))
        else:
            ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And indeed an unhandled exception &lt;em&gt;did&lt;/em&gt; end up getting raised in the above code: The &lt;code&gt;urljoin&lt;/code&gt; operation was &lt;a href=&quot;https://discuss.python.org/t/urlparse-can-sometimes-raise-an-exception-should-it/44465&quot;&gt;observed to raise an unexpected exception for certain unusual inputs&lt;/a&gt; even though it generally never raises.&lt;/p&gt;

&lt;h2&gt;Try it!&lt;/h2&gt;

&lt;p&gt;The infrastructure for using bulkheads currently lives as a utility module in the &lt;a href=&quot;https://dafoster.net/projects/crystal-web-archiver/&quot;&gt;Crystal&lt;/a&gt; project. You can install it to your local Python virtual environment using:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;python -m pip install crystal-web
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here is a small program you can run in the Python REPL that demonstrates the use of bulkheads:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&amp;gt;&amp;gt;&amp;gt; from crystal.util.bulkheads import BulkheadCell, capture_crashes_to
&amp;gt;&amp;gt;&amp;gt; 
&amp;gt;&amp;gt;&amp;gt; divide_bulkhead = BulkheadCell()
&amp;gt;&amp;gt;&amp;gt; 
&amp;gt;&amp;gt;&amp;gt; @capture_crashes_to(divide_bulkhead)
... def divide(x, y):
...     return x / y
... 
&amp;gt;&amp;gt;&amp;gt; print(divide(10, 2))
5.0
&amp;gt;&amp;gt;&amp;gt; print(divide(10, 0))
Exception in bulkhead:
Traceback (most recent call last):
  File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;
  File &quot;/Users/me/Projects/crystal-web/crystal/util/bulkheads.py&quot;, line 292, in bulkhead_call
    return func(*args, **kwargs)  # cr-traceback: ignore
  File &quot;&amp;lt;stdin&amp;gt;&quot;, line 3, in divide
ZeroDivisionError: division by zero
None
&amp;gt;&amp;gt;&amp;gt; divide_bulkhead.crash_reason
ZeroDivisionError('division by zero')
&amp;gt;&amp;gt;&amp;gt; print(divide(10, 5))
None
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See the &lt;a href=&quot;#api&quot;&gt;API&lt;/a&gt; for more detailed information about how to use bulkheads.&lt;/p&gt;

&lt;h2&gt;Appendix&lt;/h2&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#effective-critical-sections-and-bulkheads&quot;&gt;Effective Critical Sections and Bulkheads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#enforcing-that-an-error-handling-strategy-is-defined&quot;&gt;Enforcing that an error-handling strategy is defined&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#api&quot;&gt;API&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#bulkhead-api&quot;&gt;Bulkhead API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#critical-section-api&quot;&gt;Critical Section API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#error-handling-enforcement-utilities&quot;&gt;Error-handling enforcement utilities&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a name=&quot;effective-critical-sections-and-bulkheads&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Effective Critical Sections and Bulkheads&lt;/h3&gt;

&lt;p&gt;For critical sections, I&amp;rsquo;ve found it effective to protect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;listener methods&lt;/strong&gt;, since they usually operate in a different conceptual context than their caller, and it is useful to prevent crashes inside listeners from also crashing their callers;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;the run function in new threads&lt;/strong&gt;, which can capture any exception that is about to crash the thread; and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;the main function in the main thread&lt;/strong&gt;, which can capture any exception that is about to crash the thread.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For bulkheads, I&amp;rsquo;ve found it effective to protect:&lt;/p&gt;

&lt;!-- TODO: Add diagram showing nested components, and how a crash inside an inner bulkhead is quickly isolated before spreading to the entire composite, floated right. --&gt;


&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Component structures&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (which can be arranged in a tree, forming a larger &lt;a href=&quot;https://en.wikipedia.org/wiki/Composite_pattern&quot;&gt;Composite&lt;/a&gt; structure),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;certain &amp;ldquo;top-level&amp;rdquo; structures&lt;/strong&gt;&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; in the program&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;enforcing-that-an-error-handling-strategy-is-defined&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Enforcing that an error-handling strategy is defined&lt;/h3&gt;

&lt;p&gt;It can be useful for a caller to enforce that a callee has an explicitly defined error-handling strategy (via a &lt;code&gt;@capture_crashes_to*&lt;/code&gt; decorator). For example, a function that is dispatching events to listeners may want to enforce that each listener is marked with &lt;code&gt;@capture_crashes_to*&lt;/code&gt; before calling it. Such enforcement can be implemented with the following utilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;run_bulkhead_call(func)&lt;/code&gt; &amp;ndash; Calls a function after verifying it is marked with &lt;code&gt;@capture_crashes_to*&lt;/code&gt;. Raises if the function is not marked.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ensure_is_bulkhead_call(func)&lt;/code&gt; &amp;ndash; Raises if the specified function is not marked with &lt;code&gt;@capture_crashes_to*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_bulkhead_call(func)&lt;/code&gt; &amp;ndash; Returns whether the specified function is marked with &lt;code&gt;@capture_crashes_to*&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Example of an event dispatcher which enforces its listeners are marked with &lt;code&gt;@capture_crashes_to*&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def _resource_did_instantiate(self, resource: Resource) -&amp;gt; None:
    for lis in self.listeners:
        run_bulkhead_call(lis.resource_did_instantiate, resource)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See &lt;a href=&quot;#error-handling-enforcement-utilities&quot;&gt;API &gt; Error-handling enforcement utilities&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;api&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;API&lt;/h3&gt;

&lt;p&gt;Everything in this section is imported from &lt;code&gt;crystal.util.bulkheads&lt;/code&gt;. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;from crystal.util.bulkheads import Bulkhead, capture_crashes_to_stderr
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;bulkhead-api&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Bulkhead API&lt;/h4&gt;

&lt;p&gt;First, define locations where unhandled exceptions can be captured to by implementing the &lt;code&gt;Bulkhead&lt;/code&gt; protocol:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;class Bulkhead(Protocol):  # abstract
    &quot;&quot;&quot;
    A sink for unhandled exceptions (i.e. crashes).
    &quot;&quot;&quot;
    crash_reason: Optional[CrashReason]

CrashReason = BaseException
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or if you don&amp;rsquo;t want to implement your own bulkhead type, you can use the included &lt;code&gt;BulkheadCell&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;class BulkheadCell(Bulkhead):
    &quot;&quot;&quot;
    A concrete Bulkhead which stores any crash that occurs,
    but takes no special action to report such crashes.
    &quot;&quot;&quot;
    crash_reason: Optional[CrashReason]

    def __init__(self, value: Optional[CrashReason]=None) -&amp;gt; None:
        self.crash_reason = value
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;critical-section-api&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Critical Section API&lt;/h4&gt;

&lt;p&gt;Then, mark critical sections in your code with an appropriate &lt;code&gt;@capture_crashes_to*&lt;/code&gt; decorator. There are several to choose from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For critical sections defined as a method on a sensitive data structure that is its own bulkhead, &lt;code&gt;@capture_crashes_to_self&lt;/code&gt; is a good choice:&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def capture_crashes_to_self(
        bulkhead_method: Optional[Callable[Concatenate[_B, _P], _RT]]=None,
        *, return_if_crashed=None  # _RF
        ):
    &quot;&quot;&quot;
    A Bulkhead method that captures any raised exceptions to itself,
    as the &quot;crash reason&quot; of the bulkhead.

    If the bulkhead was already crashed (with a non-None &quot;crash reason&quot;) then
    this method will immediately abort, returning `return_if_crashed`.

    Examples:
        class MyBulkhead(Bulkhead):
            @capture_crashes_to_self
            def foo_did_bar(self) -&amp;gt; None:
                ...

            @capture_crashes_to_self(return_if_crashed=Ellipsis)
            def calculate_foo(self) -&amp;gt; Result:
                ...
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;For critical sections defined as a method which takes a sensitive data structure (i.e. a bulkhead) as an argument, &lt;code&gt;@capture_crashes_to_bulkhead_arg&lt;/code&gt; is a good choice:&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def capture_crashes_to_bulkhead_arg(
        method: Optional[Callable[Concatenate[_S, _B, _P], _RT]]=None,
        *, return_if_crashed=None  # _RF
        ):
    &quot;&quot;&quot;
    A method that captures any raised exceptions to its first Bulkhead argument,
    as the &quot;crash reason&quot; of the bulkhead.

    If the bulkhead was already crashed (with a non-None &quot;crash reason&quot;) then
    this method will immediately abort, returning `return_if_crashed`.

    Examples:
        class MyClass:
            @capture_crashes_to_bulkhead_arg
            def other_foo_did_bar(self, other: Bulkhead) -&amp;gt; None:
                ...

            @capture_crashes_to_bulkhead_arg(return_if_crashed=Ellipsis)
            def calculate_baz(self, other: Bulkhead) -&amp;gt; Result:
                ...
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes you may have an outer function that is already operating on a sensitive data structure (i.e. a bulkhead) which wants to define (and call) an inner function that also operates on the same structure. In that case it may be useful to protect the inner function with &lt;code&gt;@capture_crashes_to(bulkhead)&lt;/code&gt;, specifying the bulkhead to use at the time of decoration:&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def capture_crashes_to(
        bulkhead: Bulkhead,
        return_if_crashed=None  # _RF
        ) -&amp;gt; Callable[[Callable[_P, _RT]], Callable[_P, Union[_RT, _RF]]]:
    &quot;&quot;&quot;
    A method that captures any raised exceptions to the specified Bulkhead,
    as the &quot;crash reason&quot; of the bulkhead.

    If the bulkhead was already crashed (with a non-None &quot;crash reason&quot;) then
    this method will immediately abort, returning `return_if_crashed`.

    Examples:
        @capture_crashes_to(bulkhead)
        def foo_did_bar() -&amp;gt; None:
            ...

        @capture_crashes_to(bulkhead, return_if_crashed=Ellipsis)
        def calculate_foo() -&amp;gt; Result:
            ...
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;As a last resort, you may have a critical section where there is no reasonable bulkhead available to route an unhandled exception to. For example if your core error reporting infrastructure code (like a &lt;code&gt;display_error&lt;/code&gt; function) fails, the only reasonable choice may be to fallback to printing the exception to the standard error stream (&lt;code&gt;stderr&lt;/code&gt;):&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def capture_crashes_to_stderr(
        func: Optional[Callable[_P, _RT]]=None,
        *, return_if_crashed=None  # _RF
        ):
    &quot;&quot;&quot;
    A method that captures any raised exceptions, and prints them to stderr.

    Examples:
        @capture_crashes_to_stderr
        def foo(self) -&amp;gt; None:
            ...

        @capture_crashes_to_stderr(return_if_crashed=Ellipsis)
        def calculate_foo(self) -&amp;gt; Result:
            ...
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;Critical Sections (in Crystal) always print to the standard error stream&lt;/h5&gt;

&lt;p&gt;The current implementation of the &lt;code&gt;@capture_crashes_to*&lt;/code&gt; decorators in &lt;a href=&quot;https://dafoster.net/projects/crystal-web-archiver/&quot;&gt;Crystal&lt;/a&gt; always prints unhandled exceptions to &lt;code&gt;stderr&lt;/code&gt; as a side effect, to indicate that a crash happened.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most of the decorators print in &lt;strong&gt;yellow warning text&lt;/strong&gt; because the crash was presumably handled when it was routed to a bulkhead.&lt;/li&gt;
&lt;li&gt;However the &lt;code&gt;@capture_crashes_to_stderr&lt;/code&gt; decorator prints in &lt;strong&gt;red error text&lt;/strong&gt; to signal that the &lt;em&gt;only&lt;/em&gt; handling of the crash was to print it to &lt;code&gt;stderr&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In the future, if/when the &lt;code&gt;bulkheads.py&lt;/code&gt; module is extracted to its own package on PyPI, independent of Crystal, I expect I&amp;rsquo;ll alter the &lt;code&gt;@capture_crashes_to*&lt;/code&gt; decorators to NOT print anything to &lt;code&gt;stderr&lt;/code&gt; by default since I don&amp;rsquo;t think that side-effect is appropriate for all programs that may want to use these decorators.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;error-handling-enforcement-utilities&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Error-handling enforcement utilities&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def run_bulkhead_call(
        bulkhead_call: Callable[_P, _R],
        /, *args: _P.args,
        **kwargs: _P.kwargs
        ) -&amp;gt; '_R':
    &quot;&quot;&quot;
    Calls a function marked as @capture_crashes_to*,
    which does not reraise exceptions from its interior.

    Raises AssertionError if the specified function is not actually
    marked with @capture_crashes_to*.
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def ensure_is_bulkhead_call(callable: Callable) -&amp;gt; None:
    &quot;&quot;&quot;
    Raises AssertionError if the specified function is not actually
    marked with @capture_crashes_to*.
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def is_bulkhead_call(callable: Callable) -&amp;gt; bool:
    &quot;&quot;&quot;
    Returns whether the specified function is marked with @capture_crashes_to*.
    &quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;strong&gt;Component bulkhead structures&lt;/strong&gt; in my website downloader Crystal include (1) &lt;code&gt;Task&lt;/code&gt; (which compose to form the Task Tree) and (2) &lt;code&gt;entitytree.Node&lt;/code&gt; (which compose to form the Entity Tree)&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;strong&gt;Top-level bulkhead structures&lt;/strong&gt; in my website downloader Crystal include (1) the Task Scheduler itself (by using the root &lt;code&gt;Task&lt;/code&gt; as the associated bulkhead), (2) the Task Tree UI (by again using the root &lt;code&gt;Task&lt;/code&gt; as the associated bulkhead), and (3) the Entity Tree UI (which is its own bulkhead that reports errors to the Task Tree UI).&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2023/10/20/debugging-a-deadlock-in-python</id>
   <title>Debugging a deadlock in Python</title>
   <published>2023-10-20T00:00:00+00:00</published>
   <updated>2023-10-20T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2023/10/20/debugging-a-deadlock-in-python/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I recently encountered a deadlock while running the automated tests of my &lt;a href=&quot;/projects/crystal-web-archiver/&quot;&gt;website downloader, Crystal&lt;/a&gt;. The process for investigating and fixing this deadlock was interesting, so I thought I&amp;rsquo;d share it:&lt;/p&gt;

&lt;h2&gt;What does a deadlock look like?&lt;/h2&gt;

&lt;p&gt;One day after making some changes to my program, when I ran the program&amp;rsquo;s automated tests the program just completely froze, becoming unresponsive to all input and not providing any further output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ crystal --test
...
======================================================================
RUNNING: test_some_tasks_may_complete_immediately (crystal.tests.test_tasks)
----------------------------------------------------------------------
    &quot;GET /_/https/example.com/ HTTP/1.1&quot; 404 -
    *** Requested resource not in archive: https://example.com/
    &quot;GET /_/https/xkcd.com/1/ HTTP/1.1&quot; 200 -
⚠️ No further output printed. No further input accepted. Program is stuck.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To investigate why the program was frozen I wanted to &lt;strong&gt;see exactly which lines of code the program was stuck on&lt;/strong&gt;. Python has a useful &lt;a href=&quot;https://docs.python.org/3/library/faulthandler.html&quot;&gt;faulthandler&lt;/a&gt; module in the standard library that, among other things, can start listening for various Unix signals and print out a traceback showing the line of code being executed on all threads.&lt;/p&gt;

&lt;p&gt;To enable the faulthandler when running a program you can use the &lt;code&gt;PYTHONFAULTHANDLER&lt;/code&gt; environment variable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ PYTHONFAULTHANDLER=1 crystal --test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then after the program becomes stuck, you can open a new terminal window and send a SIGABRT signal to the stuck program to trigger the faulthandler:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ kill -SIGABRT 7984  # 7984 = PID of the python process
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When triggered on the Crystal program, the faulthandler printed tracebacks like:&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    faulthandler traceback
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;======================================================================
RUNNING: test_some_tasks_may_complete_immediately (crystal.tests.test_tasks)
----------------------------------------------------------------------
    &quot;GET /_/https/example.com/ HTTP/1.1&quot; 404 -
    *** Requested resource not in archive: https://example.com/
    &quot;GET /_/https/xkcd.com/1/ HTTP/1.1&quot; 200 -
Fatal Python error: Aborted

Thread 0x0000700058d9b000 (most recent call first):
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 111 in acquire
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 134 in __enter__
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 577 in __new__
  File &quot;/Users/me/Crystal/src/crystal/util/progress.py&quot;, line 143 in __init__
  ...

Thread 0x0000700057d98000 (most recent call first):
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 111 in acquire
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 134 in __enter__
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/_monitor.py&quot;, line 66 in run
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 973 in _bootstrap_inner
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 930 in _bootstrap

(... 🤔 62 copies of the above paragraph ...)

Thread 0x0000700017c55000 (most recent call first):
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/selectors.py&quot;, line 416 in select
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/socketserver.py&quot;, line 232 in serve_forever
  File &quot;/Users/me/Crystal/src/crystal/tests/test_download_body.py&quot;, line 129 in do_serve_forever
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 910 in run
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 973 in _bootstrap_inner
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 930 in _bootstrap

Thread 0x000070000ab28000 (most recent call first):
  File &quot;/Users/me/Crystal/src/crystal/tests/util/runner.py&quot;, line 130 in run
  File &quot;/Users/me/Crystal/src/crystal/util/xthreading.py&quot;, line 101 in wrapper
  File &quot;/Users/me/Crystal/src/crystal/tests/util/runner.py&quot;, line 49 in run_test
  File &quot;/Users/me/Crystal/src/crystal/util/xthreading.py&quot;, line 101 in wrapper
  File &quot;/Users/me/Crystal/src/crystal/tests/index.py&quot;, line 107 in _run_tests
  File &quot;/Users/me/Crystal/src/crystal/tests/index.py&quot;, line 80 in run_tests
  File &quot;/Users/me/Crystal/src/crystal/util/xthreading.py&quot;, line 101 in wrapper
  File &quot;/Users/me/Crystal/src/crystal/__main__.py&quot;, line 314 in bg_task
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 910 in run
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 973 in _bootstrap_inner
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 930 in _bootstrap

Current thread 0x000000011b0405c0 (most recent call first):
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/wx/core.py&quot;, line 2262 in MainLoop
  File &quot;/Users/me/Crystal/src/crystal/__main__.py&quot;, line 323 in _main
  File &quot;/Users/me/Crystal/src/crystal/__main__.py&quot;, line 45 in main
  File &quot;/Users/me/Crystal/venv3.9/bin/crystal&quot;, line 6 in &amp;lt;module&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Notice in the traceback above that several of the stuck threads are at &lt;code&gt;tqdm/std.py&quot;, line 111 in acquire&lt;/code&gt;, which is trying to acquire a low-level &lt;a href=&quot;https://docs.python.org/3/library/threading.html#threading.RLock&quot;&gt;threading.RLock&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When there is at least one thread trying to acquire a lock and not making any progress, there&amp;rsquo;s probably a deadlock.&lt;/strong&gt; So the program definitely seems to be deadlocked.&lt;/p&gt;

&lt;h2&gt;Isolating and fixing a deadlock&lt;/h2&gt;

&lt;p&gt;To debug further, it would be &lt;strong&gt;useful for the program to detect when it cannot acquire the lock it wants and then immediately print out:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;the traceback which is trying to acquire the lock&lt;/strong&gt; and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;the traceback which is currently holding the lock&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;So I made some modifications around the code that acquires/releases the lock to log that information:&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    Code to add deadlock detection and logging to lock acquire &amp; release
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;python&quot;&gt;✚ import threading
✚ import traceback

class TqdmDefaultWriteLock(object):
    th_lock = TRLock()
✚   th_lock_holders = []  # type: List[Tuple[threading.Thread, traceback.StackSummary]]

    def acquire(self, *a, **k):
✚       if 'timeout' not in k:
✚           k['timeout'] = 5.0  # seconds

        for lock in self.locks:
            ok = lock.acquire(*a, **k)
✚           if not ok:
✚               print(
✚                   f'*** TqdmDefaultWriteLock: Failed to acquire lock in '
✚                   f'{k[&quot;timeout&quot;]} seconds. '
✚                   f'Lock holder is {TqdmDefaultWriteLock.th_lock_holders[-1][0]} at:\n'
✚                   f'{&quot;&quot;.join(TqdmDefaultWriteLock.th_lock_holders[-1][1])}')
✚               print(f'*** New acquirer is:\n{&quot;&quot;.join(traceback.format_stack())}')
✚               raise AssertionError('Failed to acquire TqdmDefaultWriteLock')

✚       TqdmDefaultWriteLock.th_lock_holders.append((
✚           threading.current_thread(),
✚           traceback.format_stack()
✚       ))

    def release(self):
✚       TqdmDefaultWriteLock.th_lock_holders.pop()

        for lock in self.locks[::-1]:  # Release in inverse order of acquisition
            lock.release()
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;With those modifications in place, I can pinpoint the smoking gun:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;======================================================================
RUNNING: test_project_opens_as_readonly_when_project_is_on_readonly_filesystem (crystal.tests.test_readonly_mode)
----------------------------------------------------------------------
*** TqdmDefaultWriteLock: Failed to acquire lock in 5.0 seconds. Lock holder is &amp;lt;_MainThread(MainThread, started 4446586304)&amp;gt; at:
  ...
  File &quot;/Users/me/Crystal/src/crystal/model.py&quot;, line 679, in _apply_migrations
    self._process_table_rows(
  File &quot;/Users/me/Crystal/src/crystal/model.py&quot;, line 785, in _process_table_rows
    progress_bar.update()
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 1263, in update
    self.refresh(lock_args=self.lock_args)
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 1367, in refresh
    self._lock.acquire()

*** New acquirer is:
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 930, in _bootstrap
    self._bootstrap_inner()
  File &quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py&quot;, line 973, in _bootstrap_inner
    self.run()
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/_monitor.py&quot;, line 66, in run
    with self.tqdm_cls.get_lock():
  File &quot;/Users/me/Crystal/venv3.9/lib/python3.9/site-packages/tqdm/std.py&quot;, line 134, in __enter__
    self.acquire()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, I notice that the traceback [&lt;code&gt;_apply_migrations()&lt;/code&gt; → &lt;code&gt;_process_table_rows()&lt;/code&gt; → &lt;code&gt;update()&lt;/code&gt;] is holding the global &lt;code&gt;tqdm._lock&lt;/code&gt;, which is strange because &lt;strong&gt;there shouldn&amp;rsquo;t be a reason for this code to hold a lock at all&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;Culprit: Inappropriate locking&lt;/h3&gt;

&lt;p&gt;Originally I thought &lt;code&gt;update()&lt;/code&gt; just called &lt;code&gt;display()&lt;/code&gt; directly:&lt;/p&gt;

&lt;div class=&quot;mermaid&quot;&gt;
sequenceDiagram
    participant Project
    participant ProgressBar as ProgressBar&lt;br/&gt;(extends tqdm)
    participant lock as tqdm._lock&lt;br/&gt;«global»
    participant ProgressListener

    Project-&gt;&gt;+Project: _process_table_rows
        loop each table row
            Project-&gt;&gt;+ProgressBar: update
                ProgressBar-&gt;&gt;+ProgressBar: display [about once per second]
                ProgressBar-&gt;&gt;ProgressListener: update_gui_progress_bar_func
                deactivate ProgressBar
            deactivate ProgressBar
        end
    deactivate Project
&lt;/div&gt;


&lt;p&gt;But actually &lt;code&gt;update()&lt;/code&gt; calls a &lt;code&gt;refresh()&lt;/code&gt; method first, and &lt;em&gt;that&lt;/em&gt; call to &lt;code&gt;refresh()&lt;/code&gt; grabs the global &lt;code&gt;tqdm._lock&lt;/code&gt;!&lt;/p&gt;

&lt;div class=&quot;mermaid&quot;&gt;
sequenceDiagram
    participant Project
    participant ProgressBar as ProgressBar&lt;br/&gt;(extends tqdm)
    box rgb(191, 223, 255)
        participant lock as tqdm._lock&lt;br/&gt;«global»
    end
    participant ProgressListener

    Project-&gt;&gt;+Project: _process_table_rows
        loop each table row
            Project-&gt;&gt;+ProgressBar: update
                rect rgb(191, 223, 255)
                    note over ProgressBar,ProgressListener: ⚠️ Intermediate refresh() method acquires tqdm._lock!
                    ProgressBar-&gt;&gt;+ProgressBar: refresh [about once per second]
                        ProgressBar-&gt;&gt;lock: acquire
                        rect white
                            ProgressBar-&gt;&gt;+ProgressBar: display
                            ProgressBar-&gt;&gt;ProgressListener: update_gui_progress_bar_func
                            deactivate ProgressBar
                        end
                        ProgressBar-&gt;&gt;lock: release
                    deactivate ProgressBar
                end
            deactivate ProgressBar
        end
    deactivate Project
&lt;/div&gt;


&lt;p&gt;It makes sense for the &lt;code&gt;update()&lt;/code&gt; method on a normal &lt;code&gt;tqdm&lt;/code&gt; instance to use a lock because it prints its progress bar to a shared terminal, possibly at the same time that other instances are also trying to print to the same terminal. However the custom &lt;code&gt;ProgressBar&lt;/code&gt; subclass of &lt;code&gt;tqdm&lt;/code&gt; which is used here is displaying a &lt;em&gt;graphical&lt;/em&gt; progress bar in an unshared dialog and so it does not need to do additional locking.&lt;/p&gt;

&lt;p&gt;So we need to avoid the locking done by &lt;code&gt;refresh()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When looking at the code for that method, I notice that it&amp;rsquo;s possible to pass a &lt;code&gt;nolock=True&lt;/code&gt; argument to disable its locking behavior:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;class tqdm(...):
    def refresh(self, nolock=False, lock_args=None):
        if not nolock:
            self._lock.acquire(...)
        self.display()
        if not nolock:
            self._lock.release()
        return True
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So it should be possible to override &lt;code&gt;refresh()&lt;/code&gt; to &lt;em&gt;always&lt;/em&gt; assume &lt;code&gt;nolock=True&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ProgressBar(tqdm):
✚   @overrides
✚   def refresh(self, nolock=False, lock_args=None) -&amp;gt; bool:
✚       # Never grab the global tqdm._lock,
✚       # because we're NOT printing a CLI progress bar to a shared terminal
✚       return super().refresh(nolock=True, lock_args=lock_args)

    # Override tqdm's normal behavior of printing a CLI progress bar
    # to instead update a GUI progress bar
    @overrides
    def display(self, *args, **kwargs) -&amp;gt; None:
        update_gui_progress_bar_func(self.n, self.miniters)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lo and behold, the deadlocking behavior is no longer observed! 🎉&lt;/p&gt;

&lt;h3&gt;Common culprit: Acquiring multiple locks in an inconsistent order&lt;/h3&gt;

&lt;p&gt;Although not a problem in the above example, another common cause of deadlocks happens when a section of code acquires multiple locks at the same time but a different section of code tries to acquire the same locks in a different order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A common fix for deadlock related to acquiring locks in an inconsistent order is to give each lock a unique ID upon construction. Whenever a section of code wants to acquire multiple locks at a time, it must acquire each individual lock in increasing order of ID.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;Fin&lt;/h3&gt;

&lt;p&gt;So, that was my recent adventure in tracking down and fixing a deadlock in Python. Perhaps some of the techniques mentioned above will be helpful for you in debugging your own programs. Happy coding!&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2023/10/12/custom-file-icons-and-folder-icons</id>
   <title>Custom file icons, folder icons, and app icons on different operating systems</title>
   <published>2023-10-12T00:00:00+00:00</published>
   <updated>2023-10-12T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2023/10/12/custom-file-icons-and-folder-icons/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I recently extended my &lt;a href=&quot;/projects/crystal-web-archiver/&quot;&gt;website downloader, Crystal&lt;/a&gt;, so that the projects it creates have a proper icon on macOS, Windows, and Linux. It was a lot more challenging than I expected!&lt;/p&gt;

&lt;p&gt;Crystal organizes a group of downloaded web pages into a &lt;strong&gt;project&lt;/strong&gt;, which is a special folder containing a particular arrangement of files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ tree xkcd.crystalproj
xkcd.crystalproj      ← project
├── database.sqlite   ← web page metadata
└── revisions
    ├── 1   ← web page #1 content
    ├── 2   ← web page #2 content
    ├── 3   ← web page #3 content
    ├── 4   ← web page #4 content
    └── 5   ← web page #5 content
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;My goal was to make each of these projects appear as a &lt;em&gt;file&lt;/em&gt;, rather than as a folder, and to open in Crystal automatically when it is double-clicked on:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2023/custom-file-icons-and-folder-icons/crystalproj.png&quot; alt=&quot;A project&quot; /&gt;&lt;br/&gt;
&lt;em&gt;Looks and behaves like a file, but is secretly a folder!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Icons in macOS&lt;/h2&gt;

&lt;p&gt;On macOS it&amp;rsquo;s easy to get projects to behave the way I wanted. It&amp;rsquo;s actually common on macOS for certain types of folders - called &lt;a href=&quot;https://en.wikipedia.org/wiki/Bundle_(macOS)&quot;&gt;bundles&lt;/a&gt; - to behave like files. For example apps on macOS are themselves stored as bundles with the &lt;code&gt;.app&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;To tell macOS that folders ending with &lt;code&gt;.crystalproj&lt;/code&gt; are bundles I added the following to Crystal&amp;rsquo;s &lt;code&gt;Info.plist&lt;/code&gt; file, which is included in all macOS applications:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&amp;lt;key&amp;gt;CFBundleDocumentTypes&amp;lt;/key&amp;gt;
&amp;lt;array&amp;gt;
    &amp;lt;dict&amp;gt;
        &amp;lt;key&amp;gt;CFBundleTypeExtensions&amp;lt;/key&amp;gt;
        &amp;lt;array&amp;gt;
            &amp;lt;string&amp;gt;crystalproj&amp;lt;/string&amp;gt;
        &amp;lt;/array&amp;gt;
        &amp;lt;key&amp;gt;CFBundleTypeIconFile&amp;lt;/key&amp;gt;
        &amp;lt;string&amp;gt;DocIconMac.icns&amp;lt;/string&amp;gt;
        &amp;lt;key&amp;gt;CFBundleTypeName&amp;lt;/key&amp;gt;
        &amp;lt;string&amp;gt;Crystal Project&amp;lt;/string&amp;gt;
        &amp;lt;key&amp;gt;CFBundleTypeRole&amp;lt;/key&amp;gt;
        &amp;lt;string&amp;gt;Editor&amp;lt;/string&amp;gt;
        &amp;lt;key&amp;gt;LSTypeIsPackage&amp;lt;/key&amp;gt;
        &amp;lt;true/&amp;gt;
    &amp;lt;/dict&amp;gt;
&amp;lt;/array&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The important parts of this &lt;code&gt;Info.plist&lt;/code&gt; are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CFBundleTypeExtensions = [&amp;lsquo;crystalproj&amp;rsquo;]

&lt;ul&gt;
&lt;li&gt;Defines the extension used to recognize a project&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LSTypeIsPackage = true

&lt;ul&gt;
&lt;li&gt;Says that a project is a bundle and therefore should be treated as a file even though it is a folder&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CFBundleTypeIconFile = &amp;ldquo;DocIconMac.icns&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;Defines the name of the &lt;code&gt;.icns&lt;/code&gt; icon file to use for a project&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Setting the app icon requires similar changes to the &lt;code&gt;Info.plist&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;key&amp;gt;CFBundleIconFile&amp;lt;/key&amp;gt;
&amp;lt;string&amp;gt;AppIconMac.icns&amp;lt;/string&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Simple.&lt;/p&gt;

&lt;h2&gt;Icons in Windows&lt;/h2&gt;

&lt;p&gt;On Windows there is no concept of a &amp;ldquo;bundle&amp;rdquo;. However it is possible to give a folder a custom icon by putting &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/shell/how-to-customize-folders-with-desktop-ini&quot;&gt;a specially crafted &lt;code&gt;desktop.ini&lt;/code&gt; file&lt;/a&gt; inside of it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ cat xkcd.crystalproj/desktop.ini
[.ShellClassInfo]
DirectoryClass=crystalproj
ConfirmFileOp=0
IconFile=icons\docicon.ico
IconIndex=0
InfoTip=Crystal Project
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-folder-icon.png&quot;&gt;&lt;img alt=&quot;Diagram showing how to customize a folder's icon on Windows with desktop.ini&quot; src=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-folder-icon.png&quot; style=&quot;max-width: 100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s even possible to &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/shell/context-menu-handlers#implementing-custom-verbs-for-folders-through-desktopini&quot;&gt;tell Windows to open Crystal when the folder is double-clicked on&lt;/a&gt; by setting some registry keys:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-folder-open.png&quot;&gt;&lt;img alt=&quot;Diagram showing how to customize a folder's open action on Windows with registry keys and desktop.ini&quot; src=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-folder-open.png&quot; style=&quot;max-width: 100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-folder-open-reference.png&quot;&gt;&lt;img alt=&quot;Reference explaining how to customize a folder's open action on Windows with registry keys and desktop.ini&quot; src=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-folder-open-reference.png&quot; style=&quot;max-width: 100%; border: .5px solid black;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However it&amp;rsquo;s still possible to navigate inside of a such a folder, notably from Open and Save dialogs, so we need another way to open projects in those contexts. My solution was to add a special &amp;ldquo;opener&amp;rdquo; file inside of a project folder which could be used to open the enclosing project:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2023/custom-file-icons-and-folder-icons/crystalproj-contents.png&quot;&gt;&lt;img alt=&quot;.crystalproj folder containing a .crystalopen opener file&quot; src=&quot;/assets/2023/custom-file-icons-and-folder-icons/crystalproj-contents.png&quot; style=&quot;max-width: calc(min(488px, 100%))&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course that &lt;code&gt;.crystalopen&lt;/code&gt; file itself needs an icon. Again you can set some registry keys to tell Windows about this new file extension and its associated icon:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-file-icon.png&quot;&gt;&lt;img alt=&quot;Diagram showing how to customize a file's icon on Windows with registry keys&quot; src=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-file-icon.png&quot; style=&quot;max-width: 100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if a &lt;code&gt;.crystalopen&lt;/code&gt; file is double-clicked we want it to open Crystal, which can be configured with more registry keys:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-file-open.png&quot;&gt;&lt;img alt=&quot;Diagram showing how to customize a file's open action on Windows with registry keys&quot; src=&quot;/assets/2023/custom-file-icons-and-folder-icons/windows-customize-file-open.png&quot; style=&quot;max-width: 100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of these registry keys should be &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/setup/win-installer.iss#L13-L54&quot;&gt;set by the installer for the app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Icons in Linux&lt;/h2&gt;

&lt;p&gt;Oh Linux&amp;hellip; Icons for files, folders, and apps are displayed by the &lt;strong&gt;desktop environment&lt;/strong&gt;, and multiple such desktop environments exist for Linux. The most common ones (in 2023) seem to be &lt;strong&gt;GNOME 3&lt;/strong&gt; and &lt;strong&gt;KDE&lt;/strong&gt;, but there&amp;rsquo;s also xfce, MATE (GNOME 2), and Budgie, among others. Most of these desktop environments strive to implement the &lt;a href=&quot;https://specifications.freedesktop.org/&quot;&gt;Freedesktop Specifications&lt;/a&gt; for defining file types &amp;amp; icons, but with varying degrees of compatibility.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href=&quot;https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html&quot;&gt;Icon Theme Specification&lt;/a&gt;, which is one of the Freedesktop Specifications, an application developer &lt;em&gt;should&lt;/em&gt; be able to install icons for file types to &lt;!-- known locations in --&gt; a special &amp;ldquo;hicolor&amp;rdquo; theme which all other themes must eventually inherit from. But there are some problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://askubuntu.com/questions/52138/how-do-i-change-the-icon-for-a-particular-file-type/752316#752316&quot;&gt;GNOME doesn&amp;rsquo;t seem to implement theme inheritance correctly&lt;/a&gt;, so icons installed in the &amp;ldquo;hicolor&amp;rdquo; theme aren&amp;rsquo;t picked up by other themes. So instead of installing there I wrote a script that &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/install.py#L107-L230&quot;&gt;installed icons to every theme on the user&amp;rsquo;s system&lt;/a&gt;. &lt;a href=&quot;https://askubuntu.com/questions/1486524/how-to-set-the-icon-for-a-file-extension-in-a-portable-way-without-sudo&quot;&gt;Nobody on StackOverflow&lt;/a&gt; has been able to find a better solution so far.&lt;/li&gt;
&lt;li&gt;GNOME stores custom icon references for folders in &lt;a href=&quot;https://askubuntu.com/a/1235178/1724736&quot;&gt;the GIO database&lt;/a&gt; but KDE (and the Freedesktop Specification) use &lt;a href=&quot;https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html&quot;&gt;.directory files&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;GNOME has not one but &lt;em&gt;two&lt;/em&gt; GIO attributes for storing custom icon references, and not all programs recognize both of them:

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;metadata::custom-icon-name&lt;/code&gt; key references the name of an icon installed to a theme.

&lt;ul&gt;
&lt;li&gt;However the Desktop Icons GNOME Shell Extension, which is responsible for displaying icons on the desktop, does not understand this key!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;metadata::custom-icon&lt;/code&gt; key references a single icon file.

&lt;ul&gt;
&lt;li&gt;All programs in GNOME seem to understand this kind of key so long as you use an absolute &lt;code&gt;file://&lt;/code&gt; URL rather than an absolute or relative file path.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some programs only recognize PNG icons and other programs only recognize SVG icons, so &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/install.py#L144-L151&quot;&gt;you must install both PNG and SVG versions of each icon&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;In particular some programs in KDE only seem to recognize SVG icons even though the &lt;a href=&quot;https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html&quot;&gt;Icon Theme Specification&lt;/a&gt; implies that support for PNG icons is mandatory.&lt;/li&gt;
&lt;li&gt;GNOME by contrast seems to prefer PNG icons.&lt;/li&gt;
&lt;li&gt;If you started with only a raster version of an icon, as I did, you&amp;rsquo;ll have to vectorize the icon to make it an SVG. I had some success using the &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/resources/application-vnd.crystal.opener.svg-README.txt#L4-L11&quot;&gt;Adobe Express PNG to SVG converter tool&lt;/a&gt; to make an initial conversion and &lt;a href=&quot;https://inkscape.org/&quot;&gt;Inkscape&lt;/a&gt; for touching it up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some programs don&amp;rsquo;t notice new icons immediately after installing them.

&lt;ul&gt;
&lt;li&gt;KDE&amp;rsquo;s desktop, &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/install.py#L232-L261&quot;&gt;Plasma, must be restarted&lt;/a&gt; before it notices new icons.&lt;/li&gt;
&lt;li&gt;KDE&amp;rsquo;s file manager Dolphin doesn&amp;rsquo;t seem to notice new icons until it is restarted. Unfortunately I haven&amp;rsquo;t found a safe way to restart Dolphin without losing information about the windows and tabs it has open.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some programs - notably Open and Save dialogs - aren&amp;rsquo;t able to scale icons to the size they expect, so &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/install.py#L264-L288&quot;&gt;you must provide prescaled versions of each icon&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Scaling SVG icons isn&amp;rsquo;t particularly straightforward, but I managed to do so with the &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/resources/application-vnd.crystal.opener.svg-README.txt#L17&quot;&gt;rconvert-svg tool&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Icons for apps on the desktop don&amp;rsquo;t show up correctly in GNOME unless you &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/blob/147adc7bea1fa8d278258e75be3e51fd26892bfa/src/crystal/install.py#L84-L97&quot;&gt;set the &lt;code&gt;metadata::trusted&lt;/code&gt; GIO attribute on it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;There are probably even more issues in desktop environments other than GNOME 3 and KDE, but I did not test any additional desktop environments.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In short, my experience in getting icons to work in Linux has been a big poorly-documented mess. But after 2 weeks I did succeed!&lt;/p&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;When creating a desktop application for end users it&amp;rsquo;s important to get icons for your app and its documents configured correctly to provide a good user experience, but it getting those configurations correct can be challenging.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d like to file bugs on several Linux desktop environments so that future Linux application developers don&amp;rsquo;t have such a hard time getting icons setup, but right now I just don&amp;rsquo;t have the energy. Hopefully at least this blog post will help other application developers configure icons more quickly.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2023/08/31/how-to-make-a-binary-deb-debian-package-using-docker</id>
   <title>How to make a binary .deb Debian package using Docker</title>
   <published>2023-08-31T00:00:00+00:00</published>
   <updated>2023-08-31T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2023/08/31/how-to-make-a-binary-deb-debian-package-using-docker/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;The official instructions for making a .deb Debian package&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; I found to be
rather long-winded and fiddly, so I came up with a hopefully
more-straightforward method of building a .deb package, using Docker.&lt;/p&gt;

&lt;h2&gt;&lt;a name=&quot;deb-anatomy&quot;&gt;&lt;/a&gt;What&amp;rsquo;s in a binary .deb package?&lt;/h2&gt;

&lt;p&gt;A binary .deb package is kind of like a .zip file whose contents are unpacked
to &lt;code&gt;/&lt;/code&gt; during the installation process. For example, a simple .deb package that
installs a &lt;code&gt;hello&lt;/code&gt; program to &lt;code&gt;/usr/bin&lt;/code&gt; might have the following
structure:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ dpkg -c hello_1.0-1_darwin-amd64.deb  # show contents of .deb package
./usr/
./usr/bin/
./usr/bin/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A .deb package also contains a &lt;strong&gt;control file&lt;/strong&gt; with metadata describing the package:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ cat ./DEBIAN/control
Package: hello
Version: 1.0-1
Section: misc
Priority: optional
Architecture: all
Maintainer: David Foster &amp;lt;david@example.com&amp;gt;
Description: A program that prints a hello world message and exits.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;How can Docker be used to build a binary .deb package?&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s say you make a Dockerfile that builds and installs the &lt;code&gt;hello&lt;/code&gt; program,
based on the official build and install instructions for the program.
Such a Dockerfile might look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;dockerfile&quot;&gt;FROM debian:latest

# Install build dependencies
RUN apt-get update
RUN apt-get install build-essential -y  # install gcc

# Download source code
COPY ./hello.c /usr/src/

# Compile the binary (AKA: make)
RUN gcc -o /tmp/hello /usr/src/hello.c

# Install the binary (AKA: make install)
RUN cp /tmp/hello /usr/bin/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you build a Docker image from such a Dockerfile, each capitalized
command in the Dockerfile (like &lt;code&gt;RUN&lt;/code&gt; and &lt;code&gt;COPY&lt;/code&gt;) creates a separate &lt;strong&gt;layer&lt;/strong&gt;
which contains the files created by the command.&lt;/p&gt;

&lt;p&gt;Notably, the last &lt;code&gt;RUN&lt;/code&gt; command above which actually installs the &lt;code&gt;hello&lt;/code&gt; binary
creates a layer containing &lt;em&gt;exactly those files which should be installed&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If we could extract the files from that &amp;ldquo;install&amp;rdquo; layer then we&amp;rsquo;d have exactly
the set of files that a &lt;code&gt;hello&lt;/code&gt; .deb package should install. It turns out we &lt;em&gt;can&lt;/em&gt;!&lt;/p&gt;

&lt;h2&gt;Extracting the installed files from a Docker image layer&lt;/h2&gt;

&lt;p&gt;First build the Docker image from the Dockerfile:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ docker build -t hello-build:latest .
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then extract the contents of all Docker image layers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ mkdir build
$ docker save -o build/hello-build.tar hello-build:latest
$ cd build
$ tar xf hello-build.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see a directory structure like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ tree
.
├── 05bc8a33fbd971aa8c6d6e3613ea41f0477e4507229e6072c43f3ef61b549b82
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── 2745707919ffe930cb00def7c34e4e9bbac8e30b99f66e631edb2eb6b3a5b89c
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── 3bda020d2a872426189c67863e8add029463c14957b9fa17690e591a6a1455e2
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── 440d2890e2b9b3ce91db819ee42fb77a807daf2f46f02579a4c0df9274eebc13
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── 8c7b379494075edb4563162a9e844d548d797a470cb55c3f49f0969b9437b1e4.json
├── 9bc167af8f88fb2b70b47cc2b2be68a8be5862e49572353c13075eb5ce8845bc
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── b6100c2b22f88d1698c24d418c989bfe0174d7a4e20ca7d60824dc36d1013638
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── hello-build.tar
├── manifest.json
└── repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each of the directories with a very long name corresponds to a Docker image layer.
The contents of each directory is the set of files the layer contains.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;manifest.json&lt;/code&gt; contains information about which layer corresponds to
which directory:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ cat manifest.json | jq
[
  {
    &quot;Config&quot;: &quot;8c7b379494075edb4563162a9e844d548d797a470cb55c3f49f0969b9437b1e4.json&quot;,
    &quot;RepoTags&quot;: [
      &quot;hello-build:latest&quot;
    ],
    &quot;Layers&quot;: [
      &quot;05bc8a33fbd971aa8c6d6e3613ea41f0477e4507229e6072c43f3ef61b549b82/layer.tar&quot;,
      &quot;b6100c2b22f88d1698c24d418c989bfe0174d7a4e20ca7d60824dc36d1013638/layer.tar&quot;,
      &quot;9bc167af8f88fb2b70b47cc2b2be68a8be5862e49572353c13075eb5ce8845bc/layer.tar&quot;,
      &quot;440d2890e2b9b3ce91db819ee42fb77a807daf2f46f02579a4c0df9274eebc13/layer.tar&quot;,
      &quot;2745707919ffe930cb00def7c34e4e9bbac8e30b99f66e631edb2eb6b3a5b89c/layer.tar&quot;,
      &quot;3bda020d2a872426189c67863e8add029463c14957b9fa17690e591a6a1455e2/layer.tar&quot;
    ]
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now remember, we want to find the files in the layer for the &lt;em&gt;install&lt;/em&gt; step in the
Dockerfile, which happens to be the last step and thus also the last layer:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;dockerfile&quot;&gt;# Install the binary (AKA: make install)
RUN cp /tmp/hello /usr/bin/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So we just need to look at the last item in the &lt;code&gt;&quot;Layers&quot;&lt;/code&gt; key from the
&lt;code&gt;manifest.json&lt;/code&gt; file to find the directory we want:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&quot;3bda020d2a872426189c67863e8add029463c14957b9fa17690e591a6a1455e2/layer.tar&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So let&amp;rsquo;s unpack the files for that layer:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ export LAYER_TARFILE=&quot;3bda020d2a872426189c67863e8add029463c14957b9fa17690e591a6a1455e2/layer.tar&quot;
$ mkdir layer
$ tar Cxf layer $LAYER_TARFILE
$ cd layer
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And indeed we see the installed files:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ tree
.
└── usr
    └── bin
        └── hello
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Building a .deb package from a set of files&lt;/h2&gt;

&lt;p&gt;Remember that a binary .deb package is built from a directory of files to install
&lt;em&gt;plus&lt;/em&gt; &lt;a href=&quot;#deb-anatomy&quot;&gt;a &lt;code&gt;DEBIAN&lt;/code&gt; directory containing at least a &lt;code&gt;control&lt;/code&gt; file&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Write a &lt;code&gt;control&lt;/code&gt; file&lt;/h3&gt;

&lt;p&gt;Since we already have a directory of files to install from the last step,
we just need to add a &lt;code&gt;DEBIAN&lt;/code&gt; directory and write a &lt;code&gt;control&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ mkdir DEBIAN
$ cat &amp;gt; DEBIAN/control &amp;lt;&amp;lt;EOF
Package: hello
Version: 1.0
Section: misc
Priority: optional
Architecture: all
Maintainer: David Foster &amp;lt;david@example.com&amp;gt;
Description: Prints a hello world message and exits.
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here are some important parameters in a typical &lt;code&gt;control&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-package&quot;&gt;Package&lt;/a&gt;&lt;/strong&gt; (required) &amp;ndash; Name of the package. Used to refer to it as a dependency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-controlfields.html#version&quot;&gt;Version&lt;/a&gt;&lt;/strong&gt; (required) &amp;ndash; Version of the package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections&quot;&gt;Section&lt;/a&gt;&lt;/strong&gt; (recommended) &amp;ndash; &lt;code&gt;misc&lt;/code&gt; is fine, although a more targeted category
may make your package more discoverable if you upload it to a package archive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities&quot;&gt;Priority&lt;/a&gt;&lt;/strong&gt; (recommended) &amp;ndash; &lt;code&gt;optional&lt;/code&gt; is probably what you want.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-customized-programs.html#s-arch-spec&quot;&gt;Architecture&lt;/a&gt;&lt;/strong&gt; (required) &amp;ndash; &lt;code&gt;all&lt;/code&gt; disables machine architecture checking.
Get a list of valid architectures for your current machine using &lt;code&gt;dpkg-architecture -L&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-maintainer&quot;&gt;Maintainer&lt;/a&gt;&lt;/strong&gt; (required) &amp;ndash; The package maintainer’s name and email address.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-description&quot;&gt;Description&lt;/a&gt;&lt;/strong&gt; (required) &amp;ndash; The short description and long description of the package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps&quot;&gt;Depends&lt;/a&gt;&lt;/strong&gt; &amp;ndash; Names other packages to install alongside this package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps&quot;&gt;Recommends&lt;/a&gt;&lt;/strong&gt; &amp;ndash; Names other packages to install by default alongside this package unless
&lt;code&gt;--no-install-recommends&lt;/code&gt; is passed to &lt;code&gt;apt-get install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.debian.org/doc/debian-policy/ch-relationships.html#s-conflicts&quot;&gt;Conflicts&lt;/a&gt;&lt;/strong&gt; &amp;ndash; Names other packages whose presence will prevent this package from
being installed.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Build the &lt;code&gt;.deb&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;With the &lt;code&gt;control&lt;/code&gt; file written, we now have all files that we want to put into
the &lt;code&gt;.deb&lt;/code&gt; package. So let&amp;rsquo;s actually bundle it into a &lt;code&gt;.deb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ docker run -it -v .:/home --name deb-builder debian:latest
$$ dpkg-deb --root-owner-group --build home
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Inspect the &lt;code&gt;.deb&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;You can inspect the contents of the &lt;code&gt;.deb&lt;/code&gt; to verify that it looks reasonable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$$ dpkg -c home.deb | more  # (Optional) verify contents look OK
drwxr-xr-x root/root         0 2023-09-08 18:50 ./
drwxr-xr-x root/root         0 2023-07-25 00:00 ./usr/
drwxr-xr-x root/root         0 2023-09-08 18:46 ./usr/bin/
-rwxr-xr-x root/root     15952 2023-09-08 18:46 ./usr/bin/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Find and fix errors with Lintian&lt;/h3&gt;

&lt;p&gt;You can also use the Lintian tool to look for problems with your package:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$$ apt-get update &amp;amp;&amp;amp; apt-get install lintian -y
$$ lintian --tag-display-limit 0 home.deb  # (Optional) verify output looks OK; some ERRs are OK
E: hello: arch-independent-package-contains-binary-or-object [usr/bin/hello]
E: hello: extended-description-is-empty
E: hello: no-changelog usr/share/doc/hello/changelog.gz (native package)
E: hello: no-copyright-file
E: hello: unstripped-binary-or-object [usr/bin/hello]
W: hello: no-manual-page [usr/bin/hello]
W: hello: undeclared-elf-prerequisites (libc.so.6) [usr/bin/hello]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each line starting with &lt;code&gt;E&lt;/code&gt; is an &lt;strong&gt;error&lt;/strong&gt;, and each line starting with &lt;code&gt;W&lt;/code&gt; is a &lt;strong&gt;warning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can get a detailed description of each error by adding running lintian
with the &lt;code&gt;-i&lt;/code&gt; option:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$$ lintian -i --tag-display-limit 0 home.deb
E: hello: arch-independent-package-contains-binary-or-object [usr/bin/hello]
N: 
N:   The package contains a binary or object file but is tagged Architecture: all.
N:   
N:   If this package contains binaries or objects for cross-compiling or binary blobs for other purposes independent of the
N:   host architecture (such as BIOS updates or firmware), please add a Lintian override.
N: 
N:   Visibility: error
N:   Show-Always: no
N:   Check: binaries/architecture
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s quite possible the .deb may work as-is even if there are errors.
However it&amp;rsquo;s best to fix as many of the errors and warnings as possible.&lt;/p&gt;

&lt;p&gt;For example, to fix the following error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;W: hello: undeclared-elf-prerequisites (libc.so.6) [usr/bin/hello]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can add &lt;code&gt;Depends: libc6&lt;/code&gt; to the &lt;code&gt;control&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;Don&amp;rsquo;t install to &lt;code&gt;/usr/local&lt;/code&gt;!&lt;/h3&gt;

&lt;p&gt;A common type of error you &lt;em&gt;do&lt;/em&gt; need to fix happens when you try to install
something into &lt;code&gt;/usr/local&lt;/code&gt;, because Debian reserves the &lt;code&gt;local&lt;/code&gt; directory
for its own purposes. For example if we installed &lt;code&gt;hello&lt;/code&gt; to &lt;code&gt;/usr/local&lt;/code&gt;,
we&amp;rsquo;d see Lintian errors that look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;E: hello: dir-in-usr-local [usr/local/bin/]
E: hello: file-in-usr-local [usr/local/bin/hello]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fix those errors by altering the build process in your Dockerfile to install to
&lt;code&gt;/usr/bin&lt;/code&gt; rather than to &lt;code&gt;/usr/local/bin&lt;/code&gt;. For many Linux programs built
using a line like &lt;code&gt;./configure&lt;/code&gt;, you can usually alter that line to be
&lt;code&gt;./configure --prefix=/usr&lt;/code&gt; to configure the install process to install to
&lt;code&gt;/usr/bin&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Copy out the &lt;code&gt;.deb&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Once you&amp;rsquo;re happy with the &lt;code&gt;.deb&lt;/code&gt; package, copy it out of your build container,
give it a proper name, and exit the build container:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$$ cp home.deb /home/hello_1.0_all.deb
$$ exit
$ ls
hello_1.0_all.deb
...
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;&lt;p&gt;If you need to reenter the build container later, use:
&lt;code&gt;console
$ docker start -i deb-builder
&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Testing your .deb package&lt;/h3&gt;

&lt;p&gt;It&amp;rsquo;s a good idea to verify that package is installable.
You can do that in another fresh container:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;$ docker run -it -v .:/home --name deb-tester debian:latest
$$ apt-get update
$$ apt-get install ./home/hello_1.0_all.deb -y
$$ which hello  # ensure installed
/usr/bin/hello
$$ hello  # ensure runs
Hello world!
$$ exit
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;&lt;p&gt;If you need to reenter the testing container later, use:
&lt;code&gt;console
$ docker start -i deb-tester
&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;A complete example of all the files to build the &lt;code&gt;hello&lt;/code&gt; .deb package
is in the following GitHub repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/hello-deb-package#readme&quot;&gt;hello-deb-package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;!--
And here is a real-world example of creating a .deb package to install 
Python 2.7 in Debian 12 Bookworm:

TODO
--&gt;



&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.debian.org/Packaging&quot;&gt;https://wiki.debian.org/Packaging&lt;/a&gt;&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2023/02/22/debugging-bash-scripts-with-the-bashdb-debugger</id>
   <title>Debugging bash scripts with the bashdb debugger</title>
   <published>2023-02-22T00:00:00+00:00</published>
   <updated>2023-02-22T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2023/02/22/debugging-bash-scripts-with-the-bashdb-debugger/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Sometimes when I have a problem with a bash script I want the ability to run each line of the script one by one to see what is wrong. There is a debugger called &lt;a href=&quot;https://bashdb.sourceforge.net/&quot;&gt;bashdb&lt;/a&gt; that can be used in this way. It behaves similarly to gdb (used for debugging C and C++ programs) and pdb (used for debugging Python programs).&lt;/p&gt;

&lt;!-- 
The following commands are tested in a Linux container created with:
    $ docker run -it --rm ubuntu:latest
--&gt;


&lt;h2&gt;How to install bashdb&lt;/h2&gt;

&lt;p&gt;First you need to determine what version of bash you are running, since you need to use a corresponding version of bashdb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This version of bash is 5.1.16, so we need a bashdb version 5.1.x. Let&amp;rsquo;s download it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For versions of bashdb &amp;lt;= 5.0.x, download from: &lt;a href=&quot;https://sourceforge.net/projects/bashdb/files/bashdb/&quot;&gt;https://sourceforge.net/projects/bashdb/files/bashdb/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For versions of bashdb &gt;= 5.1.x, you must download from the associated Git branch. For example bashdb 5.1.x is in git branch &lt;a href=&quot;https://sourceforge.net/p/bashdb/code/ci/bash-5.1/tree/&quot;&gt;bash-5.1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;warning-box&quot;&gt;&lt;p&gt;NOTE: The following commands are written for an Ubuntu- or Debian-based Linux distribution. Also, you may need to prefix some commands with &lt;code&gt;sudo&lt;/code&gt; to avoid permission errors.&lt;/p&gt;
&lt;/div&gt;


&lt;pre&gt;&lt;code&gt;# apt-get update
# apt-get install git -y
# git clone https://git.code.sf.net/p/bashdb/code bashdb-code
# cd bashdb-code/
# git checkout bash-5.1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For bashdb &gt;= 5.1.x, you&amp;rsquo;ll need to build the &lt;code&gt;configure&lt;/code&gt; and &lt;code&gt;bashdb&lt;/code&gt; files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# apt-get update
# apt-get install autoconf -y  # to run autogen.sh
# apt-get install binutils -y  # to install &quot;strings&quot; tool, for autogen.sh
# apt-get install make -y  # to install &quot;make&quot; tool
# apt-get install texinfo -y  # to install &quot;makeinfo&quot; tool, for make
# ./autogen.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should now have a &lt;code&gt;bashdb&lt;/code&gt; file in the current directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# ls | grep bashdb
bashdb
bashdb-main.inc
bashdb-main.inc.in
bashdb-part2.sh
bashdb-trace
bashdb-trace.in
bashdb.in
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Optional) If you have root permissions, you can install bashdb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# make install
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;How to run bashdb&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s create an example script to debug:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# cat &amp;lt;&amp;lt; EOF &amp;gt; /tmp/hello.sh
echo 1
echo 2
echo 3
echo 4
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you did install bashdb in the step above, start the debugger on a Bash script at &lt;code&gt;/tmp/hello.sh&lt;/code&gt; with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# bash --debugger /tmp/hello.sh 
...
(/tmp/hello.sh:1):
1:  echo 1
bashdb&amp;lt;0&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you did not install bashdb, you can run the debugger by calling the bashdb script manually:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# bash ./bashdb /tmp/hello.sh 
...
(/tmp/hello.sh:1):
1:  echo 1
bashdb&amp;lt;0&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Common commands in bashdb&lt;/h2&gt;

&lt;p&gt;See all debugger commands using &lt;code&gt;help&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bashdb&amp;lt;0&amp;gt; help
Available commands:
-------------------
  action     condition  edit     frame    load     run     source  unalias  
  alias      continue   enable   handle   next     search  step    undisplay
  backtrace  debug      eval     help     print    set     step+   untrace  
  break      delete     examine  history  pwd      shell   step-   up       
  clear      disable    export   info     quit     show    tbreak  watch    
  commands   display    file     kill     return   signal  trace   watche   
  complete   down       finish   list     reverse  skip    tty   

Readline command line editing (emacs/vi mode) is available.
Type &quot;help&quot; followed by command name for full documentation.
bashdb&amp;lt;1&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See where you are in the script using &lt;code&gt;list&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bashdb&amp;lt;1&amp;gt; list
  1: =&amp;gt; echo 1
  2:    echo 2
  3:    echo 3
  4:    echo 4
  5:    
bashdb&amp;lt;2&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can &lt;strong&gt;step over&lt;/strong&gt; the current line using &lt;code&gt;next&lt;/code&gt; or &lt;code&gt;n&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bashdb&amp;lt;3&amp;gt; next
1
(/tmp/hello.sh:2):
2:  echo 2
bashdb&amp;lt;4&amp;gt; list
  1:    echo 1
  2: =&amp;gt; echo 2
  3:    echo 3
  4:    echo 4
  5:    
bashdb&amp;lt;5&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can &lt;strong&gt;step into&lt;/strong&gt; the current line using &lt;code&gt;step&lt;/code&gt; or &lt;code&gt;s&lt;/code&gt;. This is useful to enter into a function call or a line that uses &lt;code&gt;source&lt;/code&gt; to call another script:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bashdb&amp;lt;6&amp;gt; step
2
(/tmp/hello.sh:3):
3:  echo 3
bashdb&amp;lt;7&amp;gt; list
  1:    echo 1
  2:    echo 2
  3: =&amp;gt; echo 3
  4:    echo 4
  5:    
bashdb&amp;lt;8&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can &lt;strong&gt;step out&lt;/strong&gt; of the current function with &lt;code&gt;finish&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Other common commands include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;eval STATEMENT&lt;/code&gt; - Run a statement.

&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;eval X=1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;print EXPR&lt;/code&gt; - Print an expression, such as a variable.

&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;print $X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;break&lt;/code&gt; - Set a breakpoint.

&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;break 3&lt;/code&gt; (set breakpoint on line 3)&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;break /tmp/hello.sh:4&lt;/code&gt; (set breakpoint on line 4 of file &lt;code&gt;/tmp/hello&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;continue&lt;/code&gt;, &lt;code&gt;cont&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt; - Step continuously until a breakpoint is hit or the script ends.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exit&lt;/code&gt; - Stop the script and exit the debugger.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2022/07/10/crystal-1-3-0-released</id>
   <title>Crystal Web Archiver 1.3.0b Released!</title>
   <published>2022-07-10T00:00:00+00:00</published>
   <updated>2022-07-10T00:00:00+00:00</updated>
   
     <category term="DigitalPreservation"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2022/07/10/crystal-1-3-0-released/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;img class=&quot;img-box-right img-200&quot; alt=&quot;Logo: Crystal Web Archiver&quot; src=&quot;/assets/2021/crystal-web-archiver/logo@2x.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/projects/crystal-web-archiver/&quot;&gt;Crystal&lt;/a&gt; is a &lt;strong&gt;website downloader program&lt;/strong&gt; that is intended to save websites for long-term archival, even after the original site has fallen off the internet.&lt;/p&gt;

&lt;p&gt;Today&amp;rsquo;s release brings the ability to download sites requiring login, better-support for infinite-scrolling sites, a &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/wiki/Read-Only-Projects&quot;&gt;read-only mode&lt;/a&gt;, and a &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/wiki/Shell&quot;&gt;CLI shell&lt;/a&gt;. See the &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver#v130b-july-10-2022&quot;&gt;release notes&lt;/a&gt; for more information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/releases/download/v1.3.0b/crystal-win-1.3.0b.exe&quot;&gt;Download Crystal for Windows 7, 8, and 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/releases/download/v1.3.0b/crystal-mac-1.3.0b.dmg&quot;&gt;Download Crystal for macOS 10.14 and later&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;You will need to &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/issues/20&quot;&gt;right-click or Control-click on the application
and select &amp;ldquo;Open&amp;rdquo; to open it for the first time&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver#quickstart-&quot;&gt;Quickstart guide&lt;/a&gt; for downloading your first website&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a href=&quot;https://substack.com/&quot;&gt;Substack sites&lt;/a&gt; in particular can be successfully downloaded with this release of Crystal.&lt;/p&gt;

&lt;p&gt;The next release of Crystal will probably be the first final (non-beta) release, with an improved visual appearance, tutorials, and lots of documentation. See the &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/wiki/Roadmap&quot;&gt;roadmap&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Previous Releases&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/03/23/crystal-web-archiver-beta-released/&quot;&gt;Crystal 1.1.0b and 1.2.0b&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2022/07/07/compressed-text-field-for-django-and-mysql-is-released</id>
   <title>CompressedTextField for Django &amp; MySQL is released!</title>
   <published>2022-07-07T00:00:00+00:00</published>
   <updated>2022-07-07T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2022/07/07/compressed-text-field-for-django-and-mysql-is-released/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I&amp;rsquo;m proud to release &lt;a href=&quot;/projects/django-mysql-compressed-fields/&quot;&gt;django-mysql-compressed-fields&lt;/a&gt;: a new library that
provides a &lt;em&gt;compressed&lt;/em&gt; version of Django&amp;rsquo;s TextField for use with a MySQL
&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; database! This is the first library from &lt;a href=&quot;https://www.techsmart.codes/&quot;&gt;TechSmart&lt;/a&gt; to be
open-sourced. 🎉&lt;/p&gt;

&lt;p&gt;In particular you can replace a &lt;a href=&quot;https://docs.djangoproject.com/en/3.2/ref/models/fields/#textfield&quot;&gt;TextField&lt;/a&gt; or &lt;a href=&quot;https://docs.djangoproject.com/en/3.2/ref/models/fields/#charfield&quot;&gt;CharField&lt;/a&gt; like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;from django.db import models

class ProjectTextFile(models.Model):
    content = models.TextField(blank=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;from django.db import models
from mysql_compressed_fields import CompressedTextField

class ProjectTextFile(models.Model):
    content = CompressedTextField(blank=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;such that the text value of the field is actually compressed in the database.&lt;/p&gt;

&lt;p&gt;String-based lookups are supported:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;html_files = ProjectTextFile.objects.filter(content__contains='&amp;lt;html')
html_files = ProjectTextFile.objects.filter(content__startswith='&amp;lt;!DOCTYPE')
html_files = ProjectTextFile.objects.filter(content__endswith='&amp;lt;/html&amp;gt;')
empty_html_files = ProjectTextFile.objects.filter(content__in=['', '&amp;lt;html&amp;gt;&amp;lt;/html&amp;gt;'])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Advanced manipulations with MySQL&amp;rsquo;s &lt;a href=&quot;https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_compress&quot;&gt;COMPRESS()&lt;/a&gt;, &lt;a href=&quot;https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_uncompress&quot;&gt;UNCOMPRESS()&lt;/a&gt;, and
&lt;a href=&quot;https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_uncompressed-length&quot;&gt;UNCOMPRESSED_LENGTH()&lt;/a&gt; functions are also supported:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;from django.db.models import F
from mysql_compressed_fields import UncompressedLength

files = ProjectTextFile.objects.only('id').annotate(
    content_length=UncompressedLength(F('content'))
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For more information, including how to &lt;a href=&quot;https://github.com/techsmartkids/django-mysql-compressed-fields#migration-steps&quot;&gt;migrate to use CompressedTextField&lt;/a&gt;,
please see the &lt;a href=&quot;https://github.com/techsmartkids/django-mysql-compressed-fields#readme&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;My understanding is that the Postgres database - another database type that works well with Django - transparently compresses all text fields automatically, so a library like this one wouldn&amp;rsquo;t be useful for users of that database.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/03/23/crystal-web-archiver-beta-released</id>
   <title>Crystal Web Archiver 1.1.0b Released!</title>
   <published>2021-03-23T00:00:00+00:00</published>
   <updated>2021-03-23T00:00:00+00:00</updated>
   
     <category term="DigitalPreservation"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/03/23/crystal-web-archiver-beta-released/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;img class=&quot;img-box-right img-200&quot; alt=&quot;Logo: Crystal Web Archiver&quot; src=&quot;/assets/2021/crystal-web-archiver/logo@2x.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/projects/crystal-web-archiver/&quot;&gt;Crystal&lt;/a&gt; is a &lt;strong&gt;website downloader program&lt;/strong&gt; that is intended to save websites for long-term archival, even after the original site has fallen off the internet.&lt;/p&gt;

&lt;p&gt;Today I&amp;rsquo;m pleased to announce Crystal&amp;rsquo;s first beta release, bringing support for downloading more complex static sites than ever before, and generally being stable enough for a full public release.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/releases/download/v1.2.0b/crystal-win-1.2.0b.exe&quot;&gt;Download Crystal for Windows 7, 8, and 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/releases/download/v1.2.0b/crystal-mac-1.2.0b.dmg&quot;&gt;Download Crystal for macOS 10.14 and later&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;You will need to &lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver/issues/20&quot;&gt;right-click or Control-click on the application
and select &amp;ldquo;Open&amp;rdquo; to open it for the first time&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/Crystal-Web-Archiver#quickstart-&quot;&gt;Quickstart guide&lt;/a&gt; for downloading your first website&lt;/li&gt;
&lt;/ul&gt;


&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; These download links have been updated to point to the 1.2.0b release,
which has a number of fixes related to first-time-launch issues and improvements for downloading
large websites (with 10,000+ URLs).&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Many new types of sites can be successfully downloaded with this release of Crystal, including DeviantArt portfolio websites at &lt;code&gt;*.daportfolio.com&lt;/code&gt; (which are scheduled to fall off the internet in about a week after this post), &lt;a href=&quot;http://otakuworld.com/&quot;&gt;Otaku World&lt;/a&gt;, and &lt;a href=&quot;https://www.16personalities.com/&quot;&gt;16Personalities&lt;/a&gt;. &lt;!-- Some others sites of interest like [bongo.cat](https://bongo.cat/) and the [Calm Blog](https://blog.calm.com/) require additional work. --&gt;&lt;/p&gt;

&lt;h3&gt;Digital preservation is important&lt;/h3&gt;

&lt;p&gt;I personally care a lot about &lt;strong&gt;digital preservation&lt;/strong&gt;, which makes it possible to access and enjoy digital content even after it was originally released, substantially beyond the usual lifetime of such works. I&amp;rsquo;m planning to work on a few projects this year to advance the state of the art in preserving both online sites and old Macintosh programs from the 1990&amp;rsquo;s. If this topic is also of interest to you, please consider &lt;a href=&quot;javascript:scrollToSubscribeBlock();&quot;&gt;following me&lt;/a&gt; on Twitter or RSS. I like hearing from people who have similar interests.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Projects&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/projects/classicbox/&quot;&gt;ClassicBox&lt;/a&gt; - &lt;strong&gt;(Pre-alpha)&lt;/strong&gt; Makes it easy to play old Mac games from the 1990s on modern hardware, similar to the &lt;a href=&quot;https://www.dosbox.com/&quot;&gt;DOSBox&lt;/a&gt; project.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/03/16/you-might-not-need-centralized-continuous-integration</id>
   <title>You might not need centralized continuous integration</title>
   <published>2021-03-16T00:00:00+00:00</published>
   <updated>2021-03-16T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/03/16/you-might-not-need-centralized-continuous-integration/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;The general availability of easy-to-use centralized &lt;strong&gt;continuous integration&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (CI) solutions in recent years - from GitHub Actions&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; and Travis as hosted solutions, and from Jenkins&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; and Hudson as on-premises solutions - has been wonderful for allowing software to be tested continuously throughout development, catching errors early &lt;em&gt;before&lt;/em&gt; changes are merged to shared development and mainline branches.&lt;/p&gt;

&lt;p&gt;Today I&amp;rsquo;d like to explore the now perhaps-controversial idea of &amp;ldquo;When might it &lt;em&gt;not&lt;/em&gt; be worth the effort to setup a centralized continuous integration service?&amp;rdquo; In particular I&amp;rsquo;ve somehow managed to &lt;em&gt;not&lt;/em&gt; setup a CI server for the primary web app I&amp;rsquo;ve been developing and running in production even after several years.&lt;!--[^ts-platform]--&gt;&lt;/p&gt;

&lt;!-- [^ts-platform]: In case you're curious, the web app I mentioned that I've been developing for several years that currently lacks *centralized* continuous integration is the [TechSmart Platform](/projects/techsmart-platform/) for online computer science learning and coding. --&gt;


&lt;h2&gt;The wonders of continuous integration&lt;/h2&gt;

&lt;p&gt;First, I want to dispel any notion that I&amp;rsquo;m against the idea of continuous integration in general. Nothing could be further from the truth: Continuous integration - automatically running a project&amp;rsquo;s test suite against smaller branches in version control that are pending merge to a larger branch - is extremely valuable to detect new bugs as early as possible, before they reach customers and before they even reach other members of your development team. Detecting bugs early helps you ship high-quality software faster.&lt;/p&gt;

&lt;h2&gt;The trouble with &lt;em&gt;centralized&lt;/em&gt; continuous integration&lt;/h2&gt;

&lt;p&gt;That being said, &lt;em&gt;centralized&lt;/em&gt; continuous integration, where there&amp;rsquo;s a single dedicated service or server that is responsible for running CI jobs, can be complex to setup. If you&amp;rsquo;re setting up CI for a project that has only a command-line interface, is an API, or is otherwise &lt;em&gt;functional&lt;/em&gt; in design, then you should just stop here and go setup centralized CI for your project. For those cases it&amp;rsquo;s generally not that hard to setup these days. On the other hand if you&amp;rsquo;re trying to setup CI for a graphical program or something like a website that requires UI testing, then getting CI setup can be much more tricky.&lt;/p&gt;

&lt;p&gt;Now it is absolutely &lt;em&gt;possible&lt;/em&gt; to get CI setup for a project that requires graphical testing, it&amp;rsquo;s just a lot of work: You&amp;rsquo;ll probably need to automate the creation of a VM with the target operating system (through a Docker container for Linux, or a true VM for Mac or Windows), build &amp;amp; install the latest project version from source, install related web browsers and other UI tools, and setup some kind of remote graphical access (through VNC for Linux or Mac, or Remote Desktop for Windows) to debug any test failures that only occur during the CI process.&lt;/p&gt;

&lt;h2&gt;Alternative: &lt;em&gt;Distributed&lt;/em&gt; &lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; continuous integration&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s another idea: You already have a test suite that runs on your development machines right? What if you were to just lean on that existing process for your CI needs?&lt;/p&gt;

&lt;p&gt;In particular the thought is that you would make it a policy to regularly run the full test suite at certain intervals, perhaps before merging a feature branch in version control to the development branch. Or perhaps before merging the development branch to the mainline branch released to end-users and production.&lt;/p&gt;

&lt;p&gt;How might you enforce such a policy? Well, you likely already have a custom tool that helps you merge &amp;amp; release the development branch to end-users that already runs on your local development machine. What if you just add a step to that tool that runs the test suite, and have the tool only continue if the tests pass? Easy right?&lt;/p&gt;

&lt;p&gt;Of course any sufficiently large test suite - especially one interacting with a GUI or a live network - will have at least a few flaky tests that fail occasionally and cannot be fixed immediately. So there should still be a way for a developer to quickly rerun any (flaky) tests that fail so that they hopefully pass, and the developer can manually certify that all tests did eventually pass. To manually certify that all tests did pass on a particular commit, a developer could be required to manually &amp;ldquo;sign off&amp;rdquo; on the testing by typing out part of the commit&amp;rsquo;s hash, perhaps just the first few characters of it.&lt;/p&gt;

&lt;h2&gt;Putting it all together &lt;small&gt;An example distributed continuous integration system&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;Given the design above, what might an implementation of a distributed continuous integration system look like in practice? Here&amp;rsquo;s what it looks like for my primary web app, a Django-based rich web application:&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s say I&amp;rsquo;m on the tip of our development branch (&lt;code&gt;develop&lt;/code&gt;) and want to merge into the mainline branch (&lt;code&gt;main&lt;/code&gt;) and deploy to production. My Git history might look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;* a8affa5f7 &amp;lt;David Foster&amp;gt; - (main) Hotfix
| * bd8821196 &amp;lt;David Foster&amp;gt; - (HEAD -&amp;gt; develop) Feature D
| * 26adfda55 &amp;lt;David Foster&amp;gt; - Feature C
|/  
* b005bfee9 &amp;lt;David Foster&amp;gt; - Deploy to production.
|\  
| * 77e0fc2a1 &amp;lt;David Foster&amp;gt; - Feature B
| * d6f29d264 &amp;lt;David Foster&amp;gt; - Feature A
|/ 
* 588e5e61b &amp;lt;David Foster&amp;gt; - Deploy to production.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To merge I&amp;rsquo;d run our special-purpose &lt;code&gt;mergedeploy&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python3 manage.py mergedeploy
Merging: main &amp;lt;- develop
Pulling trunk and feature branches...
Creating merge commit...
Running tests...
  Log: /var/folders/vm/nd6nhd948xj4ds001s76srj80000gn/T/mergedeploy-fabs0_mt.log
CommandError: Tests failed.
Fix, commit the fix, and run: pm mergedeploy --continue
Or abort with: pm mergedeploy --abort
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Inspecting the log I see:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Creating test database for alias 'default'...
System check identified no issues (1 silenced).
......ssssssssssssssssssssssssssssssssssssssssssssF..........
----------------------------------------------------------------------
Ran 61 tests in 16.154s

FAILED (failures=1)
Destroying test database for alias 'default'...

Rerun failed tests with:
$ python3 manage.py test \
    ide.tests.PerformanceTests.test_mouse_move_near_top_of_large_program_is_fast_enough
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looks like there&amp;rsquo;s a single failing non-deterministic performance test that&amp;rsquo;s likely to be flaky. Let&amp;rsquo;s rerun it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python3 manage.py test \
    ide.tests.PerformanceTests.test_mouse_move_near_top_of_large_program_is_fast_enough
Creating test database for alias 'default'...
System check identified no issues (1 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 15.562s

OK
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Great it passed! Now all of our tests are passing.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s try the &lt;code&gt;mergedeploy&lt;/code&gt; again, using the first few characters of merge commit&amp;rsquo;s hash as our value to &amp;ldquo;sign off&amp;rdquo; that all tests did eventually pass:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git rev-parse HEAD
4dff0746ae59de693b7c5cd3a6550cad47a1e58d

$ python3 manage.py mergedeploy --continue --token=4dff07
Skipping tests because token already available.
Committing the merge...
Deploying...

Fetching latest code from Github...
Fast-forwarding deployed code to target branch...
Fetching latest submodules from Github...
Updating virtual environment...
Checking for deployment issues...
Collecting static files...
Compressing JS and CSS assets...
Building deployment archive...
Applying migrations to database...
Operations to perform:
  Apply all migrations: admin, auth, in_school, ...
Running migrations:
  Applying in_school.0073_auto_20210308_1248... OK
Uploading static files...
  Uploading: CACHE
  Uploading: everything else
Uploading deployment archive to AWS and starting deployment...
Optimizing...
  Clearing expired sessions...
  Auditing user permissions...
  Auditing primary keys...
Deployment STARTED
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;rsquo;s it! A really easy distributed continuous integration system.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/02/tests-as-policy-automation/&quot;&gt;Tests as Policy Automation&lt;/a&gt; - Has ideas for creatively using automated tests to enforce additional (non-functional) properties in your application.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code/&quot;&gt;Database clamps&lt;/a&gt; - Shows how to write deterministic performance tests for database-dependent code.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/devops/learn/what-is-continuous-integration&quot;&gt;https://docs.microsoft.com/en-us/azure/devops/learn/what-is-continuous-integration&lt;/a&gt;&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt; is my favorite hosted continution integration solution at the moment, replacing the formerly-excellent Travis, which has become unfriendly to open-source development in recent years.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jenkins.io/doc/&quot;&gt;Jenkins&lt;/a&gt; is the venerated and popular self-hosted continuous integration server that&amp;rsquo;s been around for the last decade or so.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;I call this approach &lt;em&gt;distributed&lt;/em&gt; continuous integration because it is distributed across your team&amp;rsquo;s development machines, rather than relying on being run on a central CI server or &amp;ldquo;build box&amp;rdquo;.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/03/09/reliable-rendering-of-web-pages-that-view-concurrently-modified-data</id>
   <title>Reliable rendering of web pages that view concurrently modified data</title>
   <published>2021-03-09T00:00:00+00:00</published>
   <updated>2021-03-09T00:00:00+00:00</updated>
   
     <category term="Django"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/03/09/reliable-rendering-of-web-pages-that-view-concurrently-modified-data/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Any time a backend Django or Rails function calculates something complex from the database to send to the frontend as part of a view, there is a chance the database will be modified concurrently before the view is displayed to the visitor, causing the site visitor to see outdated information.&lt;/p&gt;

&lt;p&gt;In many cases displaying stale information is fine. After all refreshing the page will bring the latest information to a visitor who is temporarily seeing stale information. But in other cases showing stale information can be a major problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For example if the stale data is some editable text that is shared with other site visitors and the new visitor tries to edit it, they&amp;rsquo;ll clobber the last set of changes made by the previous visitor! Data loss is not OK.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Or perhaps the stale information controls whether the visitor is allowed to access a piece of content that they are actively interested in. For example a user may be requesting to join a chat room and is waiting to be let in. Presenting stale access information saying that the visitor is locked out when they really aren&amp;rsquo;t will cause them to wait forever and eventually give up! Abandonment is not OK.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;How can we avoid serving stale data to the frontend to avoid such problems? This article presents one technique to both avoid serving stale data from the backend in the first place and repair the stale data quickly after page load if necessary.&lt;/p&gt;

&lt;p&gt;Although this article is written from the perspective of a Django developer, the concepts apply to any web page that is rendered dynamically based on data from a database or other data source that is subject to concurrent modification.&lt;/p&gt;

&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s start by reviewing the problem: Consider a web page that is templated by a backend server such as Django or Rails which uses information from a database. &lt;strong&gt;If visitor A reads from the database while templating such a page, but visitor B then alters the part of the database that A read, A will see outdated information&lt;/strong&gt; when her page finishes loading:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Visitor A templates a page from database data, while a visitor B makes a concurrent modification to database data&quot; src=&quot;/assets/2021/concurrent-rendering/1H-backend-interrupt.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We want to ensure that A sees the freshest data either immediately or as quickly as possible after initial page load.&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;all&quot; /&gt;&lt;/p&gt;

&lt;h2&gt;Designing a Solution&lt;/h2&gt;

&lt;p&gt;How can visitor A detect the change made by visitor B? One idea is to &lt;strong&gt;double-check the freshness of information from the database just before returning information to the frontend&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Visitor A makes one extra query to the database just before returning information to the frontend&quot; src=&quot;/assets/2021/concurrent-rendering/2H-backend-freshness-check.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Although such a strategy does narrow the time window in which a race condition could occur, it is still possible that a concurrent modification is made while the templated page is in transit to the frontend:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Visitor B makes a concurrent modification while data for Visitor A is in transit to the frontend&quot; src=&quot;/assets/2021/concurrent-rendering/3H-network-interrupt.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another idea is for the frontend to explicitly &lt;strong&gt;double-check the freshness of the information it receives from the backend shortly after it initially renders&lt;/strong&gt;. If the frontend happens to be displaying outdated information it can repair its state immediately with the new information from the backend:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Visitor A's frontend does check for any concurrent modification immediately after rendering the initial information received from the backend&quot; src=&quot;/assets/2021/concurrent-rendering/4H-frontend-freshness-check.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This strategy is almost perfect (for getting the most up-to-date state reliably to the frontend). However there&amp;rsquo;s still a narrow time window in which visitor B can make a modification after visitor A&amp;rsquo;s final request.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Visitor B makes a change slightly after visitor A's frontend makes a final freshness check&quot; src=&quot;/assets/2021/concurrent-rendering/5H-frontend-interrupt.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What now? To detect these types of concurrent changes it is necessary for the backend to &lt;strong&gt;push any new changes to the frontend in real-time (via WebSocket)&lt;/strong&gt; and the frontend needs to be prepared to receive these kinds of updates to its displayed state continuously:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Every time Visitor B makes a change, an update is pushed to Visitor A in real-time, quickly bringing Visitor A's frontend up to date.&quot; src=&quot;/assets/2021/concurrent-rendering/6H-push-fresh-data-live.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; My last article explains in depth &lt;a href=&quot;/articles/2021/03/02/real-time-updates-in-django-with-websockets-channels-and-pub-sub/&quot;&gt;how to setup such real-time updates over WebSocket in Django using Channels&lt;/a&gt;. In Rails you&amp;rsquo;d use ActionCable.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Additionally the backend must be prepared to &lt;strong&gt;push even those changes that occur between when the backend templates a view and before the frontend has connected a WebSocket&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Changes made by Visitor B are buffered so that when Visitor A's socket connects later the change is still pushed to Visitor A.&quot; src=&quot;/assets/2021/concurrent-rendering/7H-push-fresh-data-buffered.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Neither Django&amp;rsquo;s Channels nor Rails' ActionCable provide out-of-the box support for observing events that occur during this critical time period. In the &lt;a href=&quot;#implementation&quot;&gt;Implementation&lt;/a&gt; section below I outline a technique of tracking the &amp;ldquo;timepoint&amp;rdquo; an event was generated at so that it can be buffered and delivered later reliably.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Great! We&amp;rsquo;ve got a bulletproof design to quickly observe an accurate up-to-date state on the frontend. But it does seem to be rather complex&amp;hellip;&lt;/p&gt;

&lt;h2&gt;Alternative Design: No backend templating&lt;/h2&gt;

&lt;p&gt;It is &lt;em&gt;possible&lt;/em&gt; to remove the initial logic that templates information initially on the backend and &lt;strong&gt;rely entirely on the WebSocket established after frontend page load to receive both the initial page state and any updates to that state in real-time&lt;/strong&gt;. Indeed this is the approach taken by many Single Page Applications (SPAs):&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Diagram: Backend does not preload any data. Frontend pulls data and changes from backend.&quot; src=&quot;/assets/2021/concurrent-rendering/8H-push-only.svg&quot; class=&quot;sequence-diagram-h&quot; /&gt;&lt;/p&gt;

&lt;p&gt;However removing backend templating entirely will cause the initial page load to contain no content (beyond an annoying spinner) and raise your time-to-first-render. Content won&amp;rsquo;t be delivered until after JavaScript is loaded - which can take a while on mobile devices - &lt;em&gt;and&lt;/em&gt; after a socket connection is established, disproportionately slowing the browsing experience of any site visitor who isn&amp;rsquo;t on a high-end device with a fast low-latency internet connection.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d like to reach users who are on mobile devices, in rural areas, and from faraway countries where minimizing latency and bandwidth is important to avoid an unacceptable user experience. So we&amp;rsquo;re back to the more complex design with both backend templating and real-time updates&amp;hellip;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;implementation&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Implementation &lt;small&gt;(using Django)&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s actually sketch our design for reliable rendering in code!&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll use the &lt;a href=&quot;/articles/2021/03/02/real-time-updates-in-django-with-websockets-channels-and-pub-sub/#private-chat-rooms&quot;&gt;example of a User Home Page that lists a set of associated Chat Rooms&lt;/a&gt; from my last article.&lt;/p&gt;

&lt;p&gt;Please review the &lt;a href=&quot;/articles/2021/03/02/real-time-updates-in-django-with-websockets-channels-and-pub-sub/#models-consumers-and-routes&quot;&gt;User, ChatRoom, and ChatRoomJoinRequest models&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s define a &lt;strong&gt;cacheable calculation&lt;/strong&gt; for the set of available rooms given a particular user:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from typing import TypedDict

IntStr = str  # parseable as an int

class RoomInfo(TypedDict):
    id: IntStr
    title: str
    pending: bool

def calculate_chat_room_list(user: User) -&amp;gt; List[RoomInfo]:
    joined_rooms = [
        dict(
            id=str(room.id),
            title=room.title,
            pending=False,
        )
        for room in user.joined_room_set.all()
    ]
    pending_rooms = [
        dict(
            id=str(join_request.room.id),
            title=join_request.room.title,
            pending=True,
        )
        for join_request in ChatRoomJoinRequest.filter(user=user, status='pending')
    ]
    return list(sorted(
        joined_rooms + pending_rooms,
        key=lambda room_info: (room_info['title'], int(room_info['id']))
    ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in the backend view function that templates the page&amp;rsquo;s HTML, we&amp;rsquo;ll prepopulate the latest data in that HTML:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/views.py

@login_required
def user_home_page(request: HttpRequest) -&amp;gt; HttpResponse:
    ...

    last_updated = UserConsumer.create_timepoint()  # capture
    chat_room_list = calculate_chat_room_list(request.user)  # capture

    return render(request, 'chat/user_home_page.html', dict(
        user_id=str(request.user.id),
        last_updated=last_updated,
        chat_room_list=chat_room_list,
    ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then on the frontend JavaScript will wake up and establish a WebSocket connection to the backend, to see if any concurrent changes were made to the room list since the version in the HTML was calculated:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/static/chat/user_home_page.js

/*public*/ function setupUserHomePage() {
    const userId = JSON.parse(
        document.querySelector('#user-id').innerText);
    const lastUpdated = JSON.parse(
        document.querySelector('#last-updated').innerText);
    setupUserSocket(userId, lastUpdated);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whenever a user&amp;rsquo;s room join request is updated, the backend must notify the frontend appropriately through the socket by creating, buffering, and forwarding an event stamped with a new &lt;strong&gt;timepoint&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/models.py

class ChatRoomJoinRequest(models.Model):
    ...  # fields

    def save(self, *args, **kwargs) -&amp;gt; None: ...

    def notify_did_alter(self,
            action: Literal['create', 'admit', 'deny']) -&amp;gt; None:
        ...

        from chat.consumers import UserConsumer  # avoid circular import
        UserConsumer.notify_did_alter_join_request(self, action)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/consumers.py

class UserConsumer(WebsocketConsumer):
    ...

    # Send message to group
    @classmethod
    def notify_did_alter_join_request(cls,
            join_request: ChatRoomJoinRequest,
            action: Literal['create', 'admit', 'deny']) -&amp;gt; None:
        update_timepoint = cls.create_timepoint()  # capture
        async_to_sync(get_channel_layer().group_send)(
            cls.user_group_for(join_request.user_id),
            {
                'timepoint': update_timepoint,
                'type': 'did_alter_join_request',
                'kwargs': { ... }
            }
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When the frontend first connects a socket to the backend, the backend will attempt to immediately forward any events that were buffered since the timepoint passed in the connect call:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/static/chat/sockets.js

/*public*/ function setupUserSocket(userId, lastUpdated) {
    new WebSocketClient(
        '/ws/user/' + userId + '/' + lastUpdated, {
            onmessage: function(e) {
                didReceiveUserSocketMessage(JSON.parse(e.data));
            },
        }
    );
}

function didReceiveUserSocketMessage(data) {
    var type = data['type'];
    var kwargs = data['kwargs'];
    if (type === 'did_alter_join_request') {
        console.log(
            'User socket: Did alter join request: ' + 
            kwargs['action'] + ' ' + kwargs['id']);
        if (kwargs['action'] === 'create') {
            // TODO: Create a new row on User Home Page in the Rooms section
        } else if (kwargs['action'] === 'admit') {
            // TODO: Promote the row in the Rooms section to be a full room,
            //       removing the &quot;Waiting to be admitted&quot; banner
        } else if (kwargs['action'] === 'deny') {
            // TODO: Remove the row in the Rooms section
        }
    } else {
        console.warn(
            'User socket: Did receive unexpected message type: ' + type);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s it! Hopefully you found this technique useful for reliably rendering the freshest information to visitors, even in the presence of concurrent modifications.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;In &lt;span class=&quot;tag_box tag_box--inline&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&lt;a class=&quot;tag__pill&quot; href=&quot;/articles/topics/#Django&quot;&gt;
  Django&lt;sup&gt;6&lt;/sup&gt;
&lt;/a&gt;
&lt;a class=&quot;tag__subscribe subscribe&quot; href=&quot;feed://dafoster.net/articles/topics/Django.xml&quot;&gt;
  &lt;img src=&quot;/assets/feed-icon-14x14.png&quot; width=&quot;14&quot; height=&quot;14&quot; alt=&quot;Subscribe to Django&quot; title=&quot;Subscribe to Django&quot;/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/03/02/real-time-updates-in-django-with-websockets-channels-and-pub-sub/#models-consumers-and-routes&quot;&gt;Real-time updates in Django with WebSockets, Channels, and pub-sub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/16/building-web-apps-with-vue-and-django-the-ultimate-guide/&quot;&gt;Building web apps with Vue and Django - The Ultimate Guide&lt;/a&gt; - Planning how to integrate Vue with a new or existing Django app&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;A &lt;em&gt;timepoint&lt;/em&gt; represents a point in time relative to a shared clock. If you have a single shared Redis instance which you&amp;rsquo;re already using to forward socket messages, as is the case with Django&amp;rsquo;s default Channels configuration, it is convenient to use Redis&amp;rsquo;s &lt;a href=&quot;https://redis.io/commands/time&quot;&gt;TIME&lt;/a&gt; command to generate a timepoint, perhaps as part of a &lt;a href=&quot;https://redis.io/commands/eval&quot;&gt;stored procedure&lt;/a&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/03/02/real-time-updates-in-django-with-websockets-channels-and-pub-sub</id>
   <title>Real-time updates in Django with WebSockets, Channels, and pub-sub</title>
   <published>2021-03-02T00:00:00+00:00</published>
   <updated>2021-03-02T00:00:00+00:00</updated>
   
     <category term="Django"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/03/02/real-time-updates-in-django-with-websockets-channels-and-pub-sub/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;It&amp;rsquo;s easy to build a simple chat server in Channels with real-time updates&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; but it&amp;rsquo;s a bit more complicated to design a system for a more realistic (and complex) data model that has real-time updates. Here, I will show a &lt;strong&gt;publish-subscribe&lt;/strong&gt; (or &lt;strong&gt;“pub-sub”&lt;/strong&gt;) &lt;strong&gt;pattern&lt;/strong&gt; using WebSockets and Channels that can be used by your frontend to watch elements of your backend data model for updates in real-time.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#topics-and-messages&quot;&gt;Topics and Messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#public-chat-rooms&quot;&gt;Simple Example: Public Chat Rooms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#private-chat-rooms&quot;&gt;Extended Example: Private Chat Rooms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#implementation-in-django&quot;&gt;Implementation in Django&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#models-consumers-and-routes&quot;&gt;Models, Consumers, and Routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#connect-frontend-to-backend&quot;&gt;Connect Frontend to Backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#backend-can-send-messages-to-frontend&quot;&gt;Backend Can Send Messages to Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#backend-triggers-event-to-send-to-frontend&quot;&gt;Backend Triggers Event to Send to Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#wiring-up-the-user-home-page&quot;&gt;Wiring up the User Home Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#review-of-implementation&quot;&gt;Review of Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#lost-events&quot;&gt;Challenge: Lost events&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a name=&quot;topics-and-messages&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Topics and Messages&lt;/h2&gt;

&lt;p&gt;In a publish-subscribe design, frontend pages subscribe to &lt;strong&gt;topics&lt;/strong&gt; that are managed by the backend, by connecting a WebSocket to a &lt;code&gt;wss://&lt;/code&gt; backend endpoint corresponding to the topic.&lt;/p&gt;

&lt;p&gt;The backend sends &lt;strong&gt;messages&lt;/strong&gt; to a topic when taking certain actions and those messages are then forwarded on by the topic to all of its subscribers.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;public-chat-rooms&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Simple Example: Public Chat Rooms&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/pub-sub/chat-app.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: Chat app: Models, topics, and pages&quot; src=&quot;/assets/2021/pub-sub/chat-app.svg&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the context of a simple chat app, there exist Chat Rooms and Chat Messages as models in the database. There also exists a frontend Chat Room Page which is populated with the initial set of Chat Messages on page load. This page wants to observe any new Chat Messages created related to the Chat Room it&amp;rsquo;s displaying.&lt;/p&gt;

&lt;p&gt;To observe newly created Chat Messages, the Chat Room Page subscribes to a Chat Room Topic by immediately opening a WebSocket to the topic endpoint as soon as its JavaScript starts running. That topic receives messages like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    'type': 'chat_message_created',
    'kwargs': {
        'id': '42',
        'message': 'Hello world!'
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which the Chat Room Page then also receives and uses to update its local copy of Chat Messages on the page.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;private-chat-rooms&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Extended Example: Private Chat Rooms&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s say you wanted to extend your chat app such that each chat room is owned by a particular user and that other users must get permission from that owning user before they are allowed to join the room:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/pub-sub/extended-chat-app.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: Extended chat app: Models, topics, and pages&quot; src=&quot;/assets/2021/pub-sub/extended-chat-app.svg&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now there are Users, each of which has their own User Home Page which lists the set of Chat Rooms they are already members of and all Chat Rooms that they have submitted a request to join. From this page a user can navigate to a chat room or submit a request to join a new room, perhaps by providing some kind of join code associated with the room.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/pub-sub/user-home-page.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: User Home Page&quot; src=&quot;/assets/2021/pub-sub/user-home-page.svg&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally the Chat Room Page is extended so that if the person viewing the Chat Room is also the owner of the Chat Room, the page will display not just the list of users already in the room but also a list of users that have created a join request and are waiting to join the room. The owner can then choose to admit a waiting user to the room or to deny a waiting user from entering.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/pub-sub/chat-room-page.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: Chat Room Page&quot; src=&quot;/assets/2021/pub-sub/chat-room-page.svg&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now things are a bit more complicated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is now an additional User Topic that the User Home Page must subscribe to.&lt;/li&gt;
&lt;li&gt;There is a new Chat Room Join Request model to track which rooms a user has requested to join. &lt;strong&gt;Creating&lt;/strong&gt; a new request needs to be observed by the Chat Room Page in real-time so that it can display the new waiting user to the room owner. When the owner chooses to &lt;strong&gt;admit&lt;/strong&gt; or &lt;strong&gt;deny&lt;/strong&gt; the join request, that action needs to be observed in real-time on the User Home Page of the requesting user.&lt;/li&gt;
&lt;li&gt;A single model (Chat Room Join Request) can have various actions applied to it (create, admit, deny) that are observed by &lt;em&gt;multiple&lt;/em&gt; types of pages.&lt;/li&gt;
&lt;li&gt;Topics need to &lt;em&gt;authenticate&lt;/em&gt; its subscribers:

&lt;ul&gt;
&lt;li&gt;In particular the Chat Room Topic will only allow members of the Chat Room to subscribe to it.&lt;/li&gt;
&lt;li&gt;And the User Topic will only allow its related User to subscribe to it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some Topics choose to forward certain types of messages to only a &lt;em&gt;subset&lt;/em&gt; of their subscribers. In particular the Chat Room Topic should forward Chat Room Join Request messages to the room owner only and not to the other room members.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;implementation-in-django&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Implementation in Django&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;models-consumers-and-routes&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Models, Consumers, and Routes&lt;/h3&gt;

&lt;p&gt;Here&amp;rsquo;s a sketch of what an implementation of the above extended chat app might look like in Django with the Channels library.&lt;/p&gt;

&lt;p&gt;First we need some models:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# django/contrib/auth/models.py

class User(models.Model): ...  # built-in to Django
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/models.py
from django.db import models

class ChatRoom(models.Model):
    owner = models.ForeignKey(
        'User', related_name='owned_room_set', on_delete=models.PROTECT)
    title = models.CharField(max_length=50)
    member_set = models.ManyToManyField(
        'User', related_name='joined_room_set', blank=True)

class ChatMessage(models.Model):
    room = models.ForeignKey(
        'ChatRoom', related_name='message_set', on_delete=models.CASCADE)
    sender = models.ForeignKey(
        'User', related_name='message_set' on_delete=models.PROTECT)
    posted = models.DateTimeField(auto_now_add=True)
    message = models.CharField(max_length=200)

class ChatRoomJoinRequest(models.Model):
    user = models.ForeignKey(
        'User', related_name='join_request_set', on_delete=models.CASCADE)
    room = models.ForeignKey(
        'ChatRoom', related_name='join_request_set', on_delete=models.CASCADE)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then we need some topics. In Django Channels the backend object that manages a topic is called a &amp;ldquo;consumer&amp;rdquo;, so let&amp;rsquo;s create some consumers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/main/routing.py
import chat.routing
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url

application = ProtocolTypeRouter({
    # (http-&amp;gt;django views is added by default)
    'websocket': AuthMiddlewareStack(
        URLRouter(
            chat.routing.websocket_urlpatterns +
            # (add websocket_urlpatterns from more apps here)
            []
        )
    ),
})
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/routing.py
from django.conf.urls import url

from . import consumers

websocket_urlpatterns = [
    url(r'^ws/user/(?P&amp;lt;user_id&amp;gt;\d+)$', consumers.UserConsumer),
    url(r'^ws/room/(?P&amp;lt;chat_room_id&amp;gt;\d+)$', consumers.ChatRoomConsumer),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/consumers.py
from channels.generic.websocket import WebsocketConsumer

class UserConsumer(WebsocketConsumer): ...

class ChatRoomConsumer(WebsocketConsumer): ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;connect-frontend-to-backend&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Connect Frontend to Backend&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s subscribe to a topic from the frontend:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// chat_project/chat/static/chat/room.js

/*public*/ function setupChatRoomPage() {
    const roomId = ...;

    setupChatRoomSocket(roomId);  // create early to avoid missing events

    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;// chat_project/chat/static/chat/sockets.js

/*public*/ function setupChatRoomSocket(roomId) {
    new WebSocketClient(
        '/ws/room/' + roomId, {
            onmessage: function(e) {
                didReceiveChatRoomSocketMessage(JSON.parse(e.data));
            },
        }
    );
}

function didReceiveChatRoomSocketMessage(data) {
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;WebSocketClient&lt;/code&gt; opens and manages a WebSocket, transparently handling connect failures and temporary disconnections, retrying with exponential backoff and jitter. Please substitute your favorite WebSocket management library here.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Now let&amp;rsquo;s fill out the consumer on the backend so that it can accept a connection from the frontend:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/consumers.py
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from channels.layers import get_channel_layer
from chat.models import ChatRoom
from django.contrib.auth.models import User
import json

class ChatRoomConsumer(WebsocketConsumer):
    def __init__(self, *args, **kwargs) -&amp;gt; None:
        super().__init__(*args, **kwargs)
        self.user_group = None

    def connect(self) -&amp;gt; None:
        # Authenticate
        if self.user.is_anonymous:
            self.close_during_connect(code=4401)  # Unauthorized
            return

        room_id = self.scope['url_route']['kwargs']['room_id']

        # Identify requested objects
        try:
            self.room = ChatRoom.objects.get(id=room_id)
        except ChatRoom.DoesNotExist:
            self.close_during_connect(code=4404)  # Not Found
            return

        # Authorize
        if (self.user.id != self.room.owner_id and 
                self.user not in self.room.member_set.all()):
            self.close_during_connect(code=4403)  # Forbidden
            return

        # Join group
        self.room_group = self.room_group_for(room_id)
        async_to_sync(self.channel_layer.group_add)(
            self.room_group,
            self.channel_name
        )

        self.accept()

    def close_during_connect(*, code: int) -&amp;gt; None:
        self.accept()  # must accept before closing with custom code
        self.close(code=code)

    def disconnect(self, close_code) -&amp;gt; None: ...

    # === Group ===

    @staticmethod
    def room_group_for(room_id: int) -&amp;gt; str:
        return 'room_%s' % room_id

    # === Utility ===

    @property
    def user(self) -&amp;gt; User:
        return self.scope['user']
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In a regular Django view:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We&amp;rsquo;d normally use the &lt;code&gt;@login_required&lt;/code&gt; decorator
to authenticate a user but here we need to do that manually by checking
&lt;code&gt;user.is_anonymous&lt;/code&gt; and returning WS 4401 Unauthorized manually if the
user hasn&amp;rsquo;t logged in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We&amp;rsquo;d normally receive parameters from the URL as arguments to the view
function but here we have to look up the arguments manually from
&lt;code&gt;self.scope['url_route']['kwargs']['PARAMETER_NAME']&lt;/code&gt; instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When authorizing we&amp;rsquo;d normally check properties of &lt;code&gt;request.user&lt;/code&gt;
against the room ownership and membership, but here we must check
&lt;code&gt;self.user&lt;/code&gt; (which is a shortcut for &lt;code&gt;self.scope['user']&lt;/code&gt;) instead.
A failure would normally be reported using an &lt;code&gt;HttpResponseForbidden&lt;/code&gt;
but here we must manually return a WS 4403 Forbidden code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;At the end of the connection sequence the consumer adds itself to the
Channels &amp;ldquo;group&amp;rdquo; for all consumers related to the same room topic.&lt;/p&gt;

&lt;p&gt;Upon disconnection the consumer also need to unregister from the group:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ChatRoomConsumer(WebsocketConsumer):
    def __init__(self, *args, **kwargs) -&amp;gt; None: ...

    def connect(self) -&amp;gt; None: ...

    def disconnect(self, close_code) -&amp;gt; None:
        # Leave group
        if self.room_group is not None:
            async_to_sync(self.channel_layer.group_discard)(
                self.room_group,
                self.channel_name
            )

    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This consumer does not expect to &lt;em&gt;receive&lt;/em&gt; any incoming messages from the frontend; it only expects to &lt;em&gt;send&lt;/em&gt; messages to the frontend later:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ChatRoomConsumer(WebsocketConsumer):
    def __init__(self, *args, **kwargs) -&amp;gt; None: ...

    def connect(self) -&amp;gt; None: ...

    def disconnect(self, close_code) -&amp;gt; None: ...

    # Receive message from page via WebSocket
    def receive(self, text_data) -&amp;gt; None:
        pass

    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;backend-can-send-messages-to-frontend&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Backend Can Send Messages to Frontend&lt;/h3&gt;

&lt;p&gt;Okay now we have the frontend connecting to the backend. How about we trigger an event on the backend such that it gets observed by the frontend in real-time?&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create a helper method on the consumer that sends an event to all other consumers in the same topic, and forwards it on to the frontend through the consumer&amp;rsquo;s connected socket:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/consumers.py
...
from chat.models import ChatRoomJoinRequest
from typing import Literal

class ChatRoomConsumer(WebsocketConsumer):
    def __init__(self, *args, **kwargs) -&amp;gt; None: ...

    def connect(self) -&amp;gt; None: ...

    def disconnect(self, close_code) -&amp;gt; None: ...

    def receive(self, text_data) -&amp;gt; None: ...

    # Send message to group
    @classmethod
    def notify_did_alter_join_request(cls,
            join_request: ChatRoomJoinRequest,
            action: Literal['create', 'admit', 'deny']) -&amp;gt; None:
        async_to_sync(get_channel_layer().group_send)(
            cls.room_group_for(join_request.room_id),
            {
                'type': 'did_alter_join_request',
                'kwargs': {
                    'id': join_request.id,
                    'action': action,
                    'requesting_user': {
                        'id': join_request.user_id,
                        'first_name': join_request.user.first_name,
                        'last_name': join_request.user.last_name,
                    } if action == 'create' else None
                }
            }
        )

    # Receive message from group
    def did_alter_join_request(self, event) -&amp;gt; None:
        kwargs = event['kwargs']

        # Only the room owner may observe join request events so suppress for other users
        if self.user.id == self.room.owner_id:
            # Forward message to page via WebSocket
            self.send(text_data=json.dumps({
                'type': 'did_alter_join_request',
                'kwargs': {
                    'id': str(kwargs['id']),
                    'action': kwargs['action'],
                    'requesting_user': kwargs['requesting_user'],
                }
            }))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that only the room &lt;em&gt;owner&lt;/em&gt; (and not its other &lt;em&gt;members&lt;/em&gt;) are notified of events related to join-requests, since the room owner is the only one with the ability to admit or deny folks trying to join the room.&lt;/p&gt;

&lt;p&gt;Now we need to receive that forwarded event on the frontend:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// chat_project/chat/static/chat/sockets.js

/*public*/ function setupChatRoomSocket(roomId) { ... }

function didReceiveChatRoomSocketMessage(data) {
    var type = data['type'];
    var kwargs = data['kwargs'];
    if (type === 'did_alter_join_request') {
        console.log(
            'Chat room socket: Did alter join request: ' + 
            kwargs['action'] + ' ' + kwargs['id']);

        if (kwargs['action'] === 'create') {
            // TODO: Create a new row on Chat Room Page in the Members section
        } else if (kwargs['action'] === 'admit') {
            // TODO: Promote the row in the Members section to a full member of
            //       the room, removing the &quot;Deny&quot; and &quot;Allow&quot; buttons
        } else if (kwargs['action'] === 'deny') {
            // TODO: Remove the row in the Members section
        }
    } else {
        console.warn(
            'Chat room socket: Did receive unexpected message type: ' + type);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We&amp;rsquo;ve now carved out a path for events related to join-requests to be forwarded all the way to the frontend in real-time.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;backend-triggers-event-to-send-to-frontend&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Backend Triggers Event to Send to Frontend&lt;/h3&gt;

&lt;p&gt;We still need to actually &lt;em&gt;trigger&lt;/em&gt; the event in the backend by calling &lt;code&gt;ChatRoomConsumer.&lt;wbr/&gt;notify_did_alter_join_request()&lt;/code&gt; somewhere.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s make a &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; model fire a &lt;code&gt;create&lt;/code&gt; event automatically when it is created by an initial save:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/models.py

class ChatRoomJoinRequest(models.Model):
    ...  # fields

    def save(self, *args, **kwargs) -&amp;gt; None:
        change = self.id is not None  # capture
        super().save(*args, **kwargs)
        if not change:  # add
            self.notify_did_alter('create')

    def notify_did_alter(self,
            action: Literal['create', 'admit', 'deny']) -&amp;gt; None:
        from chat.consumers import ChatRoomConsumer  # avoid circular import
        ChatRoomConsumer.notify_did_alter_join_request(self, action)

        # NOTE: In the future we'll want to notify the User Home Page here too
        #from chat.consumers import UserConsumer  # avoid circular import
        #UserConsumer.notify_did_alter_join_request(self, action)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if a &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; is created in the Django admin site, its creation should be observed in real-time by the Chat Room Page. Great!&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s alter &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; such that an &lt;strong&gt;admit&lt;/strong&gt; or &lt;strong&gt;deny&lt;/strong&gt; action fires an &lt;code&gt;admit&lt;/code&gt; or &lt;code&gt;deny&lt;/code&gt; event appropriately. We can temporary add a &lt;code&gt;status&lt;/code&gt; field to the model, with a &amp;ldquo;pending&amp;rdquo;, &amp;ldquo;admitted&amp;rdquo;, or &amp;ldquo;denied&amp;rdquo; state, and listen for state changes to determine whether an &lt;code&gt;admit&lt;/code&gt; or &lt;code&gt;deny&lt;/code&gt; action has been taken:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ChatRoomJoinRequest(models.Model):
    ...  # original fields
    status = models.CharField(
        max_length=10,
        choices=[
            ('pending', '⏳ Pending'),
            ('admitted', '✅ Admitted'),
            ('denied', '✖️ Denied'),
        ],
        default='pending',
    )

    def __init__(self, *args, **kwargs) -&amp;gt; None:
        super().__init__(*args, **kwargs)
        self._initial_status = self.status

    def save(self, *args, **kwargs) -&amp;gt; None:
        change = self.id is not None  # capture
        super().save(*args, **kwargs)
        if not change:  # add
            self.notify_did_alter('create')
        else:  # change
            if self.status != self._initial_status:
                if self.status == 'admitted':
                    self.notify_did_alter('admit')
                elif self.status == 'denied':
                    self.notify_did_alter('deny')

    def notify_did_alter(self, ...): ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if the &lt;code&gt;status&lt;/code&gt; field of a &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; is changed in the Django admin site, the related &lt;code&gt;admit&lt;/code&gt; or &lt;code&gt;deny&lt;/code&gt; event should be observed in real-time by the Chat Room Page. Fantastic!&lt;/p&gt;

&lt;p&gt;Now &lt;em&gt;all&lt;/em&gt; actions that can be taken on a &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; can be observed by the Chat Room Page in real-time. ✅ But what the User Home Page? It also wants to be notified of events related to join-requests.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;wiring-up-the-user-home-page&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Wiring up the User Home Page&lt;/h3&gt;

&lt;p&gt;Recall that the User Home Page also wants to observe events related to &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt;s so that it can notify a user whether their request to join a room was approved or denied by the room owner, in real-time.&lt;/p&gt;

&lt;p&gt;Similar to how the Chat Room Page observes events in real-time, we&amp;rsquo;ll need to create a User Topic that is backed by a frontend socket and a backend consumer that manages that socket (&lt;code&gt;UserConsumer&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The code for &lt;code&gt;setupUserSocket&lt;/code&gt; is in the same pattern as that for &lt;code&gt;setupChatRoomSocket&lt;/code&gt; so I won&amp;rsquo;t bother listing it.&lt;/p&gt;

&lt;p&gt;Ditto for &lt;code&gt;UserConsumer&lt;/code&gt;, whose code is similar to that for &lt;code&gt;ChatRoomConsumer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to link &lt;code&gt;ChatRoomJoinRequest.notify_did_alter&lt;/code&gt; to notify not just the Chat Room Topic of changes, but also the User Topic via &lt;code&gt;UserConsumer.&lt;wbr/&gt;notify_did_alter_join_request&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chat_project/chat/models.py

class ChatRoomJoinRequest(models.Model):
    ...  # fields

    def save(self, *args, **kwargs) -&amp;gt; None:
        change = self.id is not None  # capture
        super().save(*args, **kwargs)
        if not change:  # add
            self.notify_did_alter('create')

    def notify_did_alter(self,
            action: Literal['create', 'admit', 'deny']) -&amp;gt; None:
        from chat.consumers import ChatRoomConsumer  # avoid circular import
        ChatRoomConsumer.notify_did_alter_join_request(self, action)

        from chat.consumers import UserConsumer  # avoid circular import
        UserConsumer.notify_did_alter_join_request(self, action)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;review-of-implementation&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Review of Implementation&lt;/h3&gt;

&lt;p&gt;Congratulations! You&amp;rsquo;ve wired up a non-trivial chat server that can admit and deny requests to join private chat rooms! 🎉&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s review how a particular sequence of actions might be taken on the backend and observed on the frontend in real-time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A staff member logs into the Django admin site and creates a &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; object:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ChatRoomJoinRequest.save()&lt;/code&gt; triggers and detects a &lt;code&gt;create&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ChatRoomJoinRequest.&lt;wbr/&gt;notify_did_alter()&lt;/code&gt; does forward the message to all interested consumers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*Consumer.&lt;wbr/&gt;notify_did_alter_join_request()&lt;/code&gt; does forward the message to the Channels group corresponding to the &lt;code&gt;*&lt;/code&gt; topic (either a Chat Room Topic or a User Topic).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*Consumer.&lt;wbr/&gt;did_alter_join_request()&lt;/code&gt; for all related consumer instances (on all backend servers) does receive the message, and forwards it on to its connected socket.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;didReceive*SocketMessage&lt;/code&gt; on either the Chat Room Page or User Home Page does receive the message, and takes action to update the page immediately. ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The staff member changes the &lt;code&gt;status&lt;/code&gt; field from its default &lt;code&gt;⏳ Pending&lt;/code&gt; value to be &lt;code&gt;✅ Admitted&lt;/code&gt;, and presses the &amp;ldquo;Save and continue&amp;rdquo; button on the admin page:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ChatRoomJoinRequest.save()&lt;/code&gt; triggers and detects an &lt;code&gt;admit&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;(&amp;hellip; same intermediate calls as above &amp;hellip;)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;didReceive*SocketMessage&lt;/code&gt; on either the Chat Room Page or User Home Page does receive the message, and takes action to update the page immediately. ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The staff member does press the &amp;ldquo;Delete&amp;rdquo; button on the admin page.

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ChatRoomJoinRequest&lt;/code&gt; model is deleted.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;lost-events&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Challenge: Lost events&lt;/h2&gt;

&lt;p&gt;The above implementation does not handle a particular race condition that can occur if an event of interest (such as the creation of a Chat Message) happens &lt;em&gt;while&lt;/em&gt; a page (like the Chat Room Page) is loading. Imagine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Alice is on the Chat Room Page and has already posted a first message to the room.&lt;/li&gt;
&lt;li&gt;User Bob requests the Chat Room Page from Django, which renders to HTML the current set of Chat Messages in the Chat Room. Bob&amp;rsquo;s Chat Room Page hasn&amp;rsquo;t yet loaded its JavaScript yet&amp;hellip;&lt;/li&gt;
&lt;li&gt;Alice posts a second message to the room, which fires a &lt;code&gt;create&lt;/code&gt; action to every loaded page that is listening to the room. However because Bob&amp;rsquo;s page hasn&amp;rsquo;t finished loading its JavaScript yet, it has not established a socket connection to the backend yet and misses the event.&lt;/li&gt;
&lt;li&gt;Bob&amp;rsquo;s JavaScript finally loads and establishes a socket connection to the backend.&lt;/li&gt;
&lt;li&gt;Alice posts a third message to the room, which get observed by Bob, now that his socket is connected.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;By the end of this story Alice has posted three messages to the chat room but Bob only sees the first and third message that Alice posted. Bob missed the second message because it was fired in between when Bob started and finished loading the Chat Room Page.&lt;/p&gt;

&lt;p&gt;How can we avoid losing events like this? &lt;a href=&quot;/articles/2021/03/09/reliable-rendering-of-web-pages-that-view-concurrently-modified-data/&quot;&gt;Join me next week&lt;/a&gt; as I sketch some solutions to this tricky scenario.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;In &lt;span class=&quot;tag_box tag_box--inline&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&lt;a class=&quot;tag__pill&quot; href=&quot;/articles/topics/#Django&quot;&gt;
  Django&lt;sup&gt;6&lt;/sup&gt;
&lt;/a&gt;
&lt;a class=&quot;tag__subscribe subscribe&quot; href=&quot;feed://dafoster.net/articles/topics/Django.xml&quot;&gt;
  &lt;img src=&quot;/assets/feed-icon-14x14.png&quot; width=&quot;14&quot; height=&quot;14&quot; alt=&quot;Subscribe to Django&quot; title=&quot;Subscribe to Django&quot;/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/16/building-web-apps-with-vue-and-django-the-ultimate-guide/&quot;&gt;Building web apps with Vue and Django - The Ultimate Guide&lt;/a&gt; - Planning how to integrate Vue with a new or existing Django app&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code/&quot;&gt;Database clamps&lt;/a&gt; - Writing deterministic performance tests for database-dependent code in Django&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/02/tests-as-policy-automation/&quot;&gt;Tests as Policy Automation&lt;/a&gt; - Has ideas for creatively using automated tests to enforce various (non-functional) properties in your Django web app.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://channels.readthedocs.io/en/latest/tutorial/&quot;&gt;official Channels tutorial&lt;/a&gt; has a nice example of building a chat server.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/02/16/building-web-apps-with-vue-and-django-the-ultimate-guide</id>
   <title>Building web apps with Vue and Django (2024) - The&amp;nbsp;Ultimate Guide</title>
   <published>2021-02-16T00:00:00+00:00</published>
   <updated>2024-06-28T00:00:00+00:00</updated>
   
     <category term="Django"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/02/16/building-web-apps-with-vue-and-django-the-ultimate-guide/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">

&lt;div class=&quot;toc toc-floating&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#1-server-or-2-servers&quot;&gt;1 server or 2 servers?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#1-server-approach&quot;&gt;1-server approach&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#bundling-strategy&quot;&gt;Bundling strategies&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#concatenated-bundling&quot;&gt;Concatenated Bundling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#import-traced-bundling&quot;&gt;Import-Traced Bundling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#transpiled-bundling&quot;&gt;Transpiled Bundling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#render-baseline-html-with-django&quot;&gt;Render baseline HTML with Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#enhance-baseline-html-with-vue&quot;&gt;Enhance baseline HTML with Vue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-server-approach&quot;&gt;2-server approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;https://vuejs.org/v2/guide/&quot;&gt;Vue&lt;/a&gt; and &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt; are both fantastic for building modern web apps - bringing declarative functional reactive programming to the frontend, and an integrated web app platform, ecosystem, and battle-hardened ORM to the backend. However they can be somewhat tricky to use &lt;em&gt;together&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here I&amp;rsquo;d like to show some approaches for setting Vue and Django up in combination for both new web apps and existing Django-based web apps. I&amp;rsquo;ve been building web apps with Django for ~9 years and with Vue for ~6 years, and in particular I&amp;rsquo;ve extensively tested the &lt;a href=&quot;#1-server-approach&quot;&gt;1&amp;#8209;server&lt;/a&gt;&amp;nbsp;&lt;a href=&quot;#concatenated-bundling&quot;&gt;concatenated bundling&lt;/a&gt; approach described below in production.&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;1-server-or-2-servers&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;1 server or 2 servers?&lt;/h1&gt;

&lt;p&gt;The first question to consider when planning to use Django and Vue together is whether to use a single server that serves both backend endpoints and frontend assets, or to use two different servers, one to host the frontend and a separate &amp;ldquo;API server&amp;rdquo; to host the backend.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/vue-and-django/1-server-vs-2-server.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: 1-server vs 2-server setup&quot; src=&quot;/assets/2021/vue-and-django/1-server-vs-2-server.svg&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Factors in favor of a 1-server setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Operational maintenance costs&lt;/strong&gt; are significantly simplified with only a single server to deploy, monitor, and manage.&lt;/li&gt;
&lt;li&gt;Relegating Django&amp;rsquo;s role to only that of an API server - in the 2-server setup - will complicate or even prevent you from using any &lt;strong&gt;Django features or third-party apps that rely on server-side rendering by Django&lt;/strong&gt;, such as its famous built-in administration interface. Instead you&amp;rsquo;ll be doing most of your server-side rendering with some JavaScript framework that is Node-compatible. And Node-based server-side rendering is generally rather complex to setup.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Factors in favor of a 2-server setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to use the latest and greatest version of JavaScript, with transpilation and module bundling, the 2-server setup has &lt;strong&gt;great community documentation for setting up a frontend server and build pipeline that supports all of these new JavaScript features&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;However most of those features can &lt;em&gt;still&lt;/em&gt; be obtained in a single-server setup with some effort, as described later in this article.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If your organization already has &lt;strong&gt;separate frontend and backend teams&lt;/strong&gt;, it may be easier to have 2 servers - one managed by the frontend team, and one managed by the backend team - to allow each team to focus on each server separately (and satisfy Conway&amp;rsquo;s Law &lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; 🙂).&lt;/li&gt;
&lt;li&gt;If your organization already has a &lt;strong&gt;separate operations team&lt;/strong&gt; that has the capacity to manage the additional server implied by a 2-server setup, then the additional operational overhead may be acceptable.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;At my company we went with the single server option because our engineering team is small (&amp;lt; 5 engineers) - so we care a lot about minimizing operational overhead - and is composed of full-stack generalists who are familar with both backend and frontend technologies - so we have engineers that can work anywhere in the stack but aggressively prefer &lt;em&gt;simple&lt;/em&gt; architechures that don&amp;rsquo;t require extreme specialization in multiple domains.&lt;/p&gt;

&lt;p&gt;In the next section I&amp;rsquo;ll drill down into the 1-server approach, but you can also skip to the &lt;a href=&quot;#2-server-approach&quot;&gt;2-server approach&lt;/a&gt; if that&amp;rsquo;s what you&amp;rsquo;re leaning toward.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;1-server-approach&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;1-server approach&lt;/h1&gt;

&lt;p&gt;When using a single server, you&amp;rsquo;ll need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pick an asset &lt;a href=&quot;#bundling-strategy&quot;&gt;bundling strategy&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#render-baseline-html-with-django&quot;&gt;render SEO-friendly HTML server-side&lt;/a&gt; with critical navigation and content available immediately on page load, and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#enhance-baseline-html-with-vue&quot;&gt;enhance that HTML client-side with Vue after page load&lt;/a&gt; with additional dynamic content.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;bundling-strategy&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Bundling strategies&lt;/h2&gt;

&lt;p&gt;When using a single integrated Django server to not only host your backend but also serve your frontend, you&amp;rsquo;ll need to decide how you want to bundle your JavaScript assets on the frontend together. &lt;strong&gt;Bundling of some kind is necessary for a production deployment&lt;/strong&gt; that is fast enough to be mobile-friendly and usable by distant international customers who may not have fast network connectivity to your server.&lt;/p&gt;

&lt;p&gt;There are multiple bundling techniques that can be used with Django, with various pros and cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#concatenated-bundling&quot;&gt;Concatenated Bundling&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#import-traced-bundling&quot;&gt;Import-Traced Bundling&lt;/a&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#transpiled-bundling&quot;&gt;Transpiled Bundling&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;concatenated-bundling&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Concatenated Bundling&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/vue-and-django/bundling-strategies/concatenated.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: Concatenated Bundling Strategy&quot; src=&quot;/assets/2021/vue-and-django/bundling-strategies/concatenated.svg&quot; class=&quot;bundling-diagram&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is by far the easiest bundling technique to use with Django and is a good technique to start with.&lt;/p&gt;

&lt;p&gt;With concatenated bundling, you write JavaScript files that consist entirely of top-level function definitions and other non-executable code. Your HTML template served by Django contains &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;-includes of every JavaScript file that the current page requires, directly or transitively. And after all JavaScript files are included the HTML page uses an inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; to call the root JavaScript function which sets up the rest of the page:&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- todo/templates/todo/todo.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;...&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;
{% compress js %}
    &amp;lt;script src=&quot;{% static 'todo/todo.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'todo/todo/list.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'todo/todo/item.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
        setupTodoPage();
    &amp;lt;/script&amp;gt;
{% endcompress %}
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;&lt;p&gt;Note: The &lt;code&gt;{% compress js %}&lt;/code&gt; tag above assumes that you are using the excellent &lt;a href=&quot;https://django-compressor.readthedocs.io/en/stable/&quot;&gt;Django Compressor&lt;/a&gt; library which integrates well with Django as your concatenating bundler.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Pros of concatenated bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Very easy to setup.&lt;/strong&gt; Leverages excellent documentation from the Django Compressor library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero bundle build times during development.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Fastest bundle build times during deployment, compared with other approaches.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Cons of concatenated bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must manage your JS dependencies in HTML manually:

&lt;ul&gt;
&lt;li&gt;Whenever adding a new JS module you must remember to add it to the HTML for the appropriate page(s).&lt;/li&gt;
&lt;li&gt;If you alter an existing JS module to depend on a new JS module, you must find all page HTMLs that include the first module and update them to include the second module if needed.&lt;/li&gt;
&lt;li&gt;If you want to avoid managing JS dependencies manually, consider &lt;a href=&quot;#import-traced-bundling&quot;&gt;import-traced bundling&lt;/a&gt; instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JavaScript files are not transformed or transpiled in any way, so if you want to use newer JavaScript features that aren&amp;rsquo;t supported by your customers' browsers then you&amp;rsquo;re out of luck. If you need transpilation consider the &lt;a href=&quot;#transpiled-bundling&quot;&gt;transpiled&lt;/a&gt; or the &lt;a href=&quot;#2-server-approach&quot;&gt;2-server&lt;/a&gt; approaches instead.&lt;/li&gt;
&lt;li&gt;It is awkward to define a class in a JavaScript module that inherits from a base class in a different module, because that &lt;em&gt;requires&lt;/em&gt; &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;-including the base class&amp;rsquo;s module first, breaking the usual rule that &amp;ldquo;the order that JS files are imported should not matter&amp;rdquo;. (However if you just limit inheritance to be within a single module or avoid it entirely, then this restriction doesn&amp;rsquo;t matter in practice.)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Note that choosing concatenated bundling does &lt;em&gt;not&lt;/em&gt; prevent you from using TypeScript-based type checking in your JS files, which I &lt;em&gt;do&lt;/em&gt; recommend for long-lived projects. In short, you can put a special &lt;code&gt;// @ts-check&lt;/code&gt; comment at the top of a JS file to &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html&quot;&gt;enable type-checking of JS with the TypeScript compiler&lt;/a&gt; (&lt;code&gt;tsc&lt;/code&gt;). &lt;!-- Using TypeScript to type-check JS files doesn't seem like a very-well known technique, so I plan to write a future article about it. --&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;import-traced-bundling&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Import-Traced Bundling&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/vue-and-django/bundling-strategies/import-traced.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: Import-Traced Bundling Strategy&quot; src=&quot;/assets/2021/vue-and-django/bundling-strategies/import-traced.svg&quot; class=&quot;bundling-diagram&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the advent of the &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt; bundler we can get all the benefits of the &lt;a href=&quot;#concatenated-bundling&quot;&gt;concatenated bundling&lt;/a&gt; approach while eliminating the need to manage JS dependencies manually, at the cost of a slightly-more-complex deployment process.&lt;/p&gt;

&lt;p&gt;With import-traced bundling, you write a root JavaScript file for each page that uses regular &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&quot;&gt;JavaScript import statements&lt;/a&gt; to bring in related modules. Your HTML template then only needs to include the root JavaScript file:&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- todo/templates/todo/todo.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;...&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;
&amp;lt;!-- js --&amp;gt;
    &amp;lt;script type=&quot;module&quot;&amp;gt;
        import { setupTodoPage } from &quot;@app/todo/todo.js&quot;;
        setupTodoPage();
    &amp;lt;/script&amp;gt;
&amp;lt;!-- endjs --&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The root JavaScript file might look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// static/todo/todo.js
import { defineTodoList } from &quot;@app/todo/list.js&quot;;

export function setupTodoPage() {
    const app = Vue.createApp(...);
    
    defineTodoList(app);
    
    app.mount(...);
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And that root JS file can include other modules like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// static/todo/list.js
import { defineTodoItem } from &quot;@app/todo/item.js&quot;;

export function defineTodoList(app) {
    app.component('todo-list', {
        props: {
            ...
        },
        template: `
            ...
        `,
        methods: {
            ...
        }
    });
    
    defineTodoItem(app);
}
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;&lt;p&gt;Note: The &lt;code&gt;import&lt;/code&gt; statements above assume that Vite has been configured to resolve &lt;code&gt;@app&lt;/code&gt; to Django&amp;rsquo;s root &lt;code&gt;static&lt;/code&gt; directory in &lt;code&gt;vite.config.js&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Some key differences between import-traced bundling and concatenated bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The HTML page only needs to include the root JS file for the page and not any of its indirect JS dependencies.&lt;/li&gt;
&lt;li&gt;JS modules must use &lt;code&gt;import&lt;/code&gt; to declare other JS modules that they depend on, and &lt;code&gt;export&lt;/code&gt; any functions that they want to be importable by other modules.&lt;/li&gt;
&lt;li&gt;JS files for &lt;em&gt;all&lt;/em&gt; Django apps in the Django project should be put in a common &lt;code&gt;static&lt;/code&gt; directory rather than using per-app &lt;code&gt;static&lt;/code&gt; directories. Having a common directory for all JS files will make it easier to configure Vite to build combined JS bundles for production deployments.

&lt;ul&gt;
&lt;li&gt;It &lt;em&gt;should&lt;/em&gt; still be possible to configure Vite to use app-specific &lt;code&gt;static&lt;/code&gt; directories, with some custom build system modifications, but I haven&amp;rsquo;t yet tried to do so myself.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Django Compressor is no longer necessary.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For a production deployment, you&amp;rsquo;ll need to alter your deployment script to run Vite on the root &lt;code&gt;static&lt;/code&gt; directory for the Django project, enumerating the set of root JS files, and generating same-named files for deployment to your static asset server.&lt;/p&gt;

&lt;p&gt;Pros of import-traced bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easy to setup for development.&lt;/strong&gt; (Trickier to setup for deployment.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero bundle build times during development.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Fast bundle build times during deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JS dependencies are automatically managed&lt;/strong&gt; through regular &lt;code&gt;import&lt;/code&gt; statements in JS.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Cons of import-traced bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript files are not transpiled at &lt;em&gt;development time&lt;/em&gt; (although they &lt;em&gt;are&lt;/em&gt; at deployment time), so if you want to use the most bleeding-edge JavaScript features that aren&amp;rsquo;t even supported by your development browser then you&amp;rsquo;re out of luck. If you need transpilation during development consider the &lt;a href=&quot;#transpiled-bundling&quot;&gt;transpiled&lt;/a&gt; or the &lt;a href=&quot;#2-server-approach&quot;&gt;2-server&lt;/a&gt; approaches instead.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To see a full example of combining Django and Vite together using the above strategy, take a look at the &lt;a href=&quot;https://github.com/techsmartkids/hello-django-vite#readme&quot;&gt;hello-django-vite&lt;/a&gt; prototype I put together.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;transpiled-bundling&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Transpiled Bundling&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2021/vue-and-django/bundling-strategies/transpiled.svg&quot;&gt;
    &lt;img alt=&quot;Diagram: Transpiled Bundling Strategy&quot; src=&quot;/assets/2021/vue-and-django/bundling-strategies/transpiled.svg&quot; class=&quot;bundling-diagram bundling-diagram-wide&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;2024 Update:&lt;/strong&gt; The &lt;a href=&quot;#import-traced-bundling&quot;&gt;import-traced bundling&lt;/a&gt; approach used with newer bundlers like Vite gives all the advantages of transpiled bundling without any of the downsides. Therefore I would not recommend a traditional transpiler approach in 2024.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;If you want the latest and greatest JavaScript features that haven&amp;rsquo;t made it even to your latest &lt;em&gt;development&lt;/em&gt; browser (ex: the latest Chrome or Firefox) then you&amp;rsquo;ll need to pay the cost of needing to transpile during development time:&lt;/p&gt;

&lt;p&gt;The transpiled bundling approach generally uses the same kind of HTML, JS, and filesystem structure as the &lt;a href=&quot;#import-traced-bundling&quot;&gt;import-traced bundling&lt;/a&gt; approach but you have additional flexibility depending on the particular set of bundler and transpiler tools you select.&lt;/p&gt;

&lt;p&gt;Common choices for transpiler tools as of mid 2024 are &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt;/&lt;a href=&quot;https://rollupjs.org/&quot;&gt;Rollup&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt;, &lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel&lt;/a&gt;, and &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pros of transpiled bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Latest bleeding-edge JavaScript features are available.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JS dependencies are automatically managed.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You can also manage dependencies automatically with the simpler &lt;a href=&quot;#import-traced-bundling&quot;&gt;import-traced bundling&lt;/a&gt; approach.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Cons of transpiled bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Moderate-to-slow bundle build times during development.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You can eliminate build times during development entirely using either the &lt;a href=&quot;#import-traced-bundling&quot;&gt;import-traced bundling&lt;/a&gt; or &lt;a href=&quot;#concatenated-bundling&quot;&gt;concatenated bundling&lt;/a&gt; approaches.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Slow bundle build times during deployment, assuming you enable aggressive optimizations.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For a sketch of how you might wire these tools together, take a look at Jacob Kaplan-Moss&amp;rsquo;s &lt;a href=&quot;https://youtu.be/E613X3RBegI?t=1203&quot;&gt;thoughts on the transpiled bundling approach at PyCon 2019&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;render-baseline-html-with-django&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Render baseline HTML with Django&lt;/h2&gt;

&lt;p&gt;Now that you&amp;rsquo;ve picked a &lt;a href=&quot;#bundling-strategy&quot;&gt;bundling approach&lt;/a&gt;, we can move on to rendering our first page with Django and Vue.&lt;/p&gt;

&lt;p&gt;When a browser (or search engine crawler) first requests a page from your site, it will only be able to immediately render the initial HTML served by Django. In particular, browsers will take some time to start running any JavaScript on your HTML page, so it&amp;rsquo;s important that the initial HTML served by Django contains your most important page content.&lt;/p&gt;

&lt;p&gt;For example if we were building the product page of an online store, we&amp;rsquo;d want to ensure the initial HTML rendered by Django immediately contained things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the site logo and top navigation links,&lt;/li&gt;
&lt;li&gt;the product image,&lt;/li&gt;
&lt;li&gt;the product description,&lt;/li&gt;
&lt;li&gt;placeholders for other less-important panels that are okay to load later in JavaScript, with appropriate animated spinner icons or other loading indicators.&lt;/li&gt;
&lt;/ul&gt;


&lt;!-- (TODO: Diagram: Example product page after initial page load) --&gt;


&lt;p&gt;So the HTML rendered by Django might look something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- store/templates/store/product.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;...&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;!-- Top navigation --&amp;gt;
    &amp;lt;nav class=&quot;navbar navbar-inverse&quot;&amp;gt;
        &amp;lt;div class=&quot;container-fluid&quot;&amp;gt;
            &amp;lt;div class=&quot;navbar-header&quot;&amp;gt;
                &amp;lt;!-- Site logo --&amp;gt;
                &amp;lt;a class=&quot;navbar-brand&quot; href=&quot;/&quot;&amp;gt;Acme Store&amp;lt;/a&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;navbar-collapse collapse&quot;&amp;gt;
                &amp;lt;!-- Top navigation links --&amp;gt;
                &amp;lt;ul class=&quot;nav navbar-nav&quot;&amp;gt;
                    &amp;lt;li&amp;gt;&amp;lt;a href=&quot;/computer-systems/&quot;&amp;gt;Computer Systems&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
                    &amp;lt;li&amp;gt;&amp;lt;a href=&quot;/components/&quot;&amp;gt;Components&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
                    &amp;lt;li&amp;gt;&amp;lt;a href=&quot;/electronics/&quot;&amp;gt;Electronics&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
                    ...
                &amp;lt;/ul&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/nav&amp;gt;
    
    &amp;lt;!-- Main content --&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
        &amp;lt;div class=&quot;content-container&quot;&amp;gt;
            &amp;lt;!-- Primary panel --&amp;gt;
            &amp;lt;img alt=&quot;Product image&quot; href=&quot;{{ product.image_url }}&quot; style=&quot;float: left;&quot; /&amp;gt;
            &amp;lt;h1&amp;gt;{{ product.title }}&amp;lt;/h1&amp;gt;
            &amp;lt;div&amp;gt;
                {{ product.description }}
            &amp;lt;/div&amp;gt;
            
            &amp;lt;!-- Secondary panel; a placeholder filled out by JS later --&amp;gt;
            &amp;lt;div id=&quot;recommendations-panel&quot;&amp;gt;
                &amp;lt;h2&amp;gt;Recommended for You&amp;lt;/h2&amp;gt;
                &amp;lt;img
                    v-if=&quot;loading&quot; 
                    alt=&quot;Loading spinner&quot;
                    src=&quot;{% static 'store/loading-spinner.gif' %}&quot; /&amp;gt;
                &amp;lt;template
                    v-else
                    v-cloak&amp;gt;
                    ...
                &amp;lt;/template&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;

{{ recommendations_panel_data|json_script:&quot;recommendations-panel-data&quot; }}

{% compress js %}
    &amp;lt;script src=&quot;{% static 'store/product.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'store/product/recommendations.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
        setupProductPage();
    &amp;lt;/script&amp;gt;
{% endcompress %}
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Notice that most of the page is initially rendered server-side with Django&amp;rsquo;s built-in templating system and &lt;em&gt;not&lt;/em&gt; with Vue. This server-side rendered content loads fast and can be appropriately indexed by search engines for better SEO.&lt;/p&gt;

&lt;p&gt;However certain less-important panels like the Recommendations panel don&amp;rsquo;t need to be loaded immediately and will be given life by Vue later after the page&amp;rsquo;s JavaScript starts running. Let&amp;rsquo;s consider how that works:&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;enhance-baseline-html-with-vue&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Enhance baseline HTML with Vue&lt;/h2&gt;

&lt;p&gt;When the browser (or search engine) first loads the Recommendations panel it will initially see just a loading spinner:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;recommendations-panel&quot;&amp;gt;
    &amp;lt;h2&amp;gt;Recommended for You&amp;lt;/h2&amp;gt;
    &amp;lt;img
        v-if=&quot;loading&quot; 
        alt=&quot;Loading spinner&quot;
        src=&quot;{% static 'store/loading-spinner.gif' %}&quot; /&amp;gt;
    &amp;lt;template
        v-else
        v-cloak&amp;gt;
        ...
    &amp;lt;/template&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;&lt;p&gt;Note: The &lt;code&gt;v-cloak&lt;/code&gt; directive is associated with the CSS rule &lt;code&gt;[v-cloak] { display: none; }&lt;/code&gt; so nothing marked by that directive will be displayed initially.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Later when the page&amp;rsquo;s JavaScript starts running, it will call &lt;code&gt;setupProductPage()&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// store/product.js
/*public*/ function setupProductPage() {
    setupRecommendationsPanel();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which will call &lt;code&gt;setupRecommendationsPanel()&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// store/product/recommendations.js
/*public*/ function setupRecommendationsPanel() {
    Vue.createApp({
        data() {
            return JSON.parse(document.querySelector('#recommendations-panel-data').innerText);
        },
        computed: {
            loading() {
                ...
            },
            ...
        },
        methods: {
            ...
        }
    }).mount('#recommendations-panel');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which will use Vue to render the interior of the panel, perhaps after performing an Ajax request back to a Django endpoint to fetch more data.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Notice that some data for the panel can be prepopulated in HTML via the &lt;code&gt;{{ ...|json_script:&quot;...&quot; }}&lt;/code&gt; template tag by Django and then fetched later via &lt;code&gt;document.querySelector(...).innerText&lt;/code&gt; in JavaScript.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Done! Skip to the &lt;a href=&quot;#conclusion&quot;&gt;conclusion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;2-server-approach&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;2-server approach&lt;/h1&gt;

&lt;p&gt;When using a separate frontend server for Vue and a separate backend server for Django, you&amp;rsquo;ll need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup &lt;a href=&quot;https://v3.vuejs.org/guide/installation.html#installation&quot;&gt;a standalone Vue server&lt;/a&gt; and &lt;a href=&quot;https://www.djangoproject.com/start/&quot;&gt;a standalone Django server&lt;/a&gt; using official documentation from each project,&lt;/li&gt;
&lt;li&gt;alter the frontend Vue server to &lt;a href=&quot;https://ssr.vuejs.org/#why-ssr&quot;&gt;support server-side rendering or prerendering&lt;/a&gt; using official documentation,&lt;/li&gt;
&lt;li&gt;create some pages in Vue, some endpoints in Django (perhaps using the &lt;a href=&quot;https://www.django-rest-framework.org/&quot;&gt;Django REST Framework&lt;/a&gt;), and have those pages access those routes using plain old &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch&quot;&gt;window.fetch()&lt;/a&gt;&amp;nbsp;(or something shinier like &lt;a href=&quot;https://github.com/axios/axios#readme&quot;&gt;Axios&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;conclusion&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Hopefully this guide has been useful in helping you setup Vue inside your new or existing Django web app. Happy coding!&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code/&quot;&gt;Database clamps&lt;/a&gt; - Writing deterministic performance tests for database-dependent code in Django&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/02/tests-as-policy-automation/&quot;&gt;Tests as Policy Automation&lt;/a&gt; - Has ideas for creatively using automated tests to enforce various (non-functional) properties in your Django web app.&lt;/li&gt;
&lt;li&gt;Other &lt;span class=&quot;tag_box tag_box--inline&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&lt;a class=&quot;tag__pill&quot; href=&quot;/articles/topics/#Django&quot;&gt;
Django&lt;sup&gt;6&lt;/sup&gt;
&lt;/a&gt;
&lt;a class=&quot;tag__subscribe subscribe&quot; href=&quot;feed://dafoster.net/articles/topics/Django.xml&quot;&gt;
&lt;img src=&quot;/assets/feed-icon-14x14.png&quot; width=&quot;14&quot; height=&quot;14&quot; alt=&quot;Subscribe to Django&quot; title=&quot;Subscribe to Django&quot;/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/span&gt; articles&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Projects&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/projects/techsmart-platform&quot;&gt;TechSmart Platform&lt;/a&gt; - Large web app that I work on that uses Django and Vue. (Sorry it’s closed-source!)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_law&quot;&gt;Conway&amp;rsquo;s Law&lt;/a&gt;: The technical architecture of a system tends to mirror the organizational and communication structure of the people that build it. So if you have 2 teams building a compiler, they&amp;rsquo;re likely to build a 2-pass compiler. Similarly if you have a frontend and a backend team, they&amp;rsquo;re likely to build separate frontend and backend servers if left to themselves.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;At the time of writing it takes 2.1 seconds for me to bundle 100,650 lines (5,304 KiB) of JS and 17,617 lines (699 KiB) of CSS using Django Compressor&amp;rsquo;s default settings which uses &lt;a href=&quot;http://opensource.perlig.de/rjsmin/&quot;&gt;rJSMin&lt;/a&gt; to minify JS (via &lt;a href=&quot;https://stackoverflow.com/a/1732454/604063&quot;&gt;regex&lt;/a&gt; no less!).&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code</id>
   <title>Database clamps: Deterministic performance tests for database-dependent code</title>
   <published>2021-02-09T00:00:00+00:00</published>
   <updated>2021-02-09T00:00:00+00:00</updated>
   
     <category term="Django"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;If you&amp;rsquo;ve got a moderate-sized &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt; web application then you&amp;rsquo;re probably already writing automated tests to make sure none of its pages break unexpectedly when you&amp;rsquo;re making changes to them. That is, you&amp;rsquo;re testing page &lt;em&gt;functionality&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However another way that pages can break is that they take too long to display, or otherwise don&amp;rsquo;t have enough &lt;em&gt;performance&lt;/em&gt;. The very first Django application I deployed to customers got crushed with only &lt;em&gt;12&lt;/em&gt; concurrent users! How embarassing! 🤭 I hadn&amp;rsquo;t even bothered to do basic performance testing before that initial deployment because I didn&amp;rsquo;t think it was &lt;em&gt;possible&lt;/em&gt; for such a small number of expected users to bring down my site. I now know better and require that any new web page have &lt;strong&gt;automated performance tests&lt;/strong&gt; before being deployed to customers.&lt;/p&gt;

&lt;p&gt;There are many kinds of performance tests, but right now I&amp;rsquo;d like to focus on automated &lt;em&gt;database&lt;/em&gt; performance tests, or what I like to call &lt;strong&gt;database clamps&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;What are they?&lt;/h3&gt;

&lt;p&gt;A database clamp measures the number of database queries issued when a web page is being rendered server-side. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from django.test import TestCase

class TodoListPageTests(TestCase):
    ...

    def test_todo_list_mdp(self):  # mdp = maintains database performance
        self.client.login(username='user', password='password')
        with self.assertNumQueries(3):  # &amp;lt;-- DATABASE CLAMP
            response = self.client.get(reverse('todo:list'))
            self.assertEqual(200, response.status_code)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, &lt;a href=&quot;https://docs.djangoproject.com/en/3.1/topics/testing/tools/#django.test.TransactionTestCase.assertNumQueries&quot;&gt;assertNumQueries&lt;/a&gt; is used to clamp the number of database queries issued when the &lt;code&gt;todo:list&lt;/code&gt; page is rendered server-side. If any changes are made to the the page that increases (or otherwise changes) the number of database queries issued, then the test will detect the change and fail.&lt;/p&gt;

&lt;h3&gt;Why are they useful?&lt;/h3&gt;

&lt;p&gt;Database clamps are particularly useful for web applications because &lt;strong&gt;server-side rendering time is typically dominated by database query time&lt;/strong&gt;. If you get your database access patterns under control then it&amp;rsquo;s likely the remaining server-side rendering time will be negligible.&lt;/p&gt;

&lt;p&gt;Also, unlike most &lt;a href=&quot;/articles/2018/06/02/performance-testing/&quot;&gt;other kinds of performance tests&lt;/a&gt;, database clamps are fully &lt;em&gt;deterministic&lt;/em&gt; and always give consistent results no matter how fast the machine the test is being run on. Very useful!&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Avoid the embarassment of your site falling over when only a handful of customers try to use it. Use database clamps!&lt;/p&gt;

&lt;h3&gt;Appendix: Better database clamps&lt;/h3&gt;

&lt;p&gt;A database clamp which uses Django&amp;rsquo;s &lt;a href=&quot;https://docs.djangoproject.com/en/3.1/topics/testing/tools/#django.test.TransactionTestCase.assertNumQueries&quot;&gt;assertNumQueries&lt;/a&gt; function will fail not just when the number of database queries &lt;em&gt;increases&lt;/em&gt; (which is usually a problem) but will also fail when the number of queries &lt;em&gt;decreases&lt;/em&gt; (which is usually okay, and even desirable).&lt;/p&gt;

&lt;p&gt;In my own Django web application I use a custom version of &lt;code&gt;assertNumQueries&lt;/code&gt; that still fails if the number of queries &lt;em&gt;increases&lt;/em&gt; but only issues a warning (via &lt;code&gt;warnings.warn(...)&lt;/code&gt;) if the number of queries &lt;em&gt;decreases&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python3 manage.py test gradebook
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.758s

OK

Warnings:
gradebook/tests/test_gradebook.py:425: UserWarning: 14 database queries executed, no more than 15 expected. Consider reducing the expected query count to match.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In addition, my version of &lt;code&gt;assertNumQueries&lt;/code&gt; expects to be called from an automated test method whose name contains the word &lt;code&gt;mdp&lt;/code&gt; (&amp;ldquo;maintains database performance&amp;rdquo;) and warns if it is being called from a test lacking that acronym. This restriction allows my engineering team to easily search for and run exactly those tests which use database clamps when making large scale changes that may break many database clamps at once:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python3 manage.py test $(python3 manage.py list_tests mdp -s)
System check identified no issues (0 silenced).
..............s..s..................................................
----------------------------------------------------------------------
Ran X tests in Ys

OK (skipped=Z)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2018/06/02/performance-testing/&quot;&gt;Performance Testing&lt;/a&gt; - Details a few of the big guns of performance testing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/02/tests-as-policy-automation/&quot;&gt;Tests as Policy Automation&lt;/a&gt; - Has more ideas for creatively using automated tests to enforce additional (non-functional) properties in your backend web application.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/02/02/tests-as-policy-automation</id>
   <title>Tests as Policy Automation</title>
   <published>2021-02-02T00:00:00+00:00</published>
   <updated>2021-02-02T00:00:00+00:00</updated>
   
     <category term="Django"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/02/02/tests-as-policy-automation/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Automated tests are usually used for testing functional requirements of your product code. But they can &lt;em&gt;also&lt;/em&gt; be used to enforce other policies and coding practices as well.&lt;/p&gt;

&lt;p&gt;If writing a web application it&amp;rsquo;s likely you already have a rule like &amp;ldquo;all automated tests must pass before any new version of the web application can be deployed to customers on the production environment&amp;rdquo;. In that case any new policies you want to enforce regularly can be added to your standard automated test suite and they will necessarily have to be satisfied on every deployment!&lt;/p&gt;

&lt;p&gt;Here are some example of special policies I&amp;rsquo;ve enforced from the automated test suite of &lt;a href=&quot;/projects/techsmart-platform/&quot;&gt;a large web application I work on&lt;/a&gt; (which uses &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt;, Python+&lt;a href=&quot;http://mypy-lang.org/index.html&quot;&gt;mypy&lt;/a&gt;, and JavaScript+TypeScript as core technologies):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the typechecker reports no errors

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;type_&lt;wbr/&gt;checker_&lt;wbr/&gt;reports_&lt;wbr/&gt;no_&lt;wbr/&gt;errors_&lt;wbr/&gt;in_&lt;wbr/&gt;python&lt;/code&gt; &lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;type_&lt;wbr/&gt;checker_&lt;wbr/&gt;reports_&lt;wbr/&gt;no_&lt;wbr/&gt;errors_&lt;wbr/&gt;in_&lt;wbr/&gt;typed_&lt;wbr/&gt;javascript&lt;/code&gt; &lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ban unsafe coding patterns by inspecting source code

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;no_&lt;wbr/&gt;new_&lt;wbr/&gt;fragile_&lt;wbr/&gt;test_&lt;wbr/&gt;suites&lt;/code&gt;&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;ensure_&lt;wbr/&gt;all_&lt;wbr/&gt;directories_&lt;wbr/&gt;containing_&lt;wbr/&gt;py_&lt;wbr/&gt;files_&lt;wbr/&gt;have_&lt;wbr/&gt;init_&lt;wbr/&gt;file&lt;/code&gt;&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ensure hard-coded debug modes are turned off

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;the_&lt;wbr/&gt;debug_&lt;wbr/&gt;toolbar_&lt;wbr/&gt;is_&lt;wbr/&gt;disabled&lt;/code&gt; &lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;that_&lt;wbr/&gt;compress_&lt;wbr/&gt;is_&lt;wbr/&gt;enabled&lt;/code&gt; &lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ensure test-only environmental settings are correctly configured

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;that_&lt;wbr/&gt;tests_&lt;wbr/&gt;do_&lt;wbr/&gt;not_&lt;wbr/&gt;send_&lt;wbr/&gt;real_&lt;wbr/&gt;emails&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ensure invariants that should apply to all types of a large/unbounded number of domain objects are satisfied:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;all_&lt;wbr/&gt;django_&lt;wbr/&gt;add_&lt;wbr/&gt;and_&lt;wbr/&gt;edit_&lt;wbr/&gt;admin_&lt;wbr/&gt;pages_&lt;wbr/&gt;render&lt;/code&gt; &lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; 👈 &lt;strong&gt;especially useful and powerful&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;every_&lt;wbr/&gt;block_&lt;wbr/&gt;type_&lt;wbr/&gt;satisfies_&lt;wbr/&gt;all_&lt;wbr/&gt;block_&lt;wbr/&gt;standards&lt;/code&gt; &lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;c_&lt;wbr/&gt;blocks_&lt;wbr/&gt;for_&lt;wbr/&gt;python_&lt;wbr/&gt;blocks_&lt;wbr/&gt;must_&lt;wbr/&gt;use_&lt;wbr/&gt;consistent_&lt;wbr/&gt;indent_&lt;wbr/&gt;width&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;every_&lt;wbr/&gt;field_&lt;wbr/&gt;id_&lt;wbr/&gt;must_&lt;wbr/&gt;use_&lt;wbr/&gt;underscore_&lt;wbr/&gt;case&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;every_&lt;wbr/&gt;block_&lt;wbr/&gt;type_&lt;wbr/&gt;whose_&lt;wbr/&gt;codegen_&lt;wbr/&gt;always_&lt;wbr/&gt;references_&lt;wbr/&gt;x_&lt;wbr/&gt;library_&lt;wbr/&gt;must_&lt;wbr/&gt;import_&lt;wbr/&gt;x_&lt;wbr/&gt;library&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip; (9 more)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Prevent certain configuration settings from changing without triggering a discussion with Product Management, the Business, or your Dev Lead

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test_&lt;wbr/&gt;max_&lt;wbr/&gt;redirect_&lt;wbr/&gt;count_&lt;wbr/&gt;is_&lt;wbr/&gt;5&lt;/code&gt; &lt;sup id=&quot;fnref:9&quot;&gt;&lt;a href=&quot;#fn:9&quot; rel=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Hopefully these examples give you some ideas of some special policies you might enforce in your own automated test suite. Happy coding!&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sirupsen.com/shitlists/&quot; class=&quot;external&quot;&gt;Shitlist Driven Development&lt;/a&gt; - Gives techniques for how to effectively apply automated policy changes of the type discussed in this article at &lt;em&gt;large&lt;/em&gt; scale.&lt;/li&gt;
&lt;/ul&gt;


&lt;!-- * [Performance Testing](/articles/2018/06/02/performance-testing/) --&gt;


&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code/&quot;&gt;Database clamps: Deterministic performance tests for database-dependent code&lt;/a&gt; - Shows how to clamp the database performance of server-side rendering using automated tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;TechSmart&amp;rsquo;s backend Python and Django code is typechecked using the &lt;a href=&quot;http://mypy-lang.org/&quot;&gt;mypy&lt;/a&gt; type checker.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;TechSmart&amp;rsquo;s frontend JavaScript code is typechecked using the &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; compiler, &lt;code&gt;tsc&lt;/code&gt;.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;In this context a &amp;ldquo;fragile test suite&amp;rdquo; corresponds to a subclass of Django&amp;rsquo;s &lt;code&gt;StaticLiveServerTestCase&lt;/code&gt; or &lt;code&gt;TestCase&lt;/code&gt; whose &lt;code&gt;setUpClass&lt;/code&gt; method fails to use a &lt;code&gt;try-finally&lt;/code&gt; to invoke &lt;code&gt;super().tearDownClass()&lt;/code&gt; explicitly if something goes wrong partway through the test suite setup. This fragile-detection metatest walks through all test suite classes and uses Python&amp;rsquo;s &lt;code&gt;inspect.getsourcelines&lt;/code&gt; to read the source code of all test classes to look for the absense of the proper kind of try-finally.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;It is important for any directory containing Python source files (&lt;code&gt;*.py&lt;/code&gt;) to contain an &lt;code&gt;__init__.py&lt;/code&gt; file so that the directory is marked properly as a Python package and is recognized correctly by Python typecheckers like mypy.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/jazzband/django-debug-toolbar#readme&quot;&gt;Django Debug Toolbar&lt;/a&gt; is an amazingly useful tool to profile the database queries that your Django-rendered page is making.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;TechSmart&amp;rsquo;s frontend JavaScript code is concatentated and minified using the excellent &lt;a href=&quot;https://pypi.org/project/django-compressor/&quot;&gt;Django Compressor&lt;/a&gt; app. At some point we may migrate instead to using &lt;a href=&quot;https://www.snowpack.dev/&quot;&gt;Snowpack&lt;/a&gt;, a lightweight module bundler.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;The &amp;ldquo;all Django Add and Edit pages must render&amp;rdquo; metatest automatically discovers all Django models and related pages that exist in Django&amp;rsquo;s admin site. Then it tries to navigate to each such admin page and ensures that it renders completely. This metatest has caught cases where some of our more complex custom admin pages broke due to a code change elsewhere.&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;The &amp;ldquo;blocks&amp;rdquo; referred to here are the lego-like blocks which snap together to form programs in the visual &lt;a href=&quot;/projects/skylark/&quot;&gt;Skylark language&lt;/a&gt;.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:9&quot;&gt;
&lt;p&gt;The Python IDE &lt;!-- TODO: Make non-redirecting DPython project page --&gt; in the TechSmart Platform contains an API-compatible reimplementation of the popular &lt;a href=&quot;https://pypi.org/project/requests/&quot;&gt;Requests&lt;/a&gt; HTTP client library so that students can write programs that access the internet, in a controlled fashion.&lt;a href=&quot;#fnref:9&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/01/26/python's-type-checking-renaissance</id>
   <title>Python's type checking renaissance</title>
   <published>2021-01-26T00:00:00+00:00</published>
   <updated>2022-03-29T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/01/26/python's-type-checking-renaissance/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;You may have heard that TypeScript has been taking the web development space by storm in the &lt;a href=&quot;https://2018.stateofjs.com/javascript-flavors/typescript/&quot;&gt;last&lt;/a&gt; &lt;a href=&quot;https://2019.stateofjs.com/javascript-flavors/typescript/&quot;&gt;few&lt;/a&gt; &lt;a href=&quot;https://2020.stateofjs.com/en-US/technologies/javascript-flavors/&quot;&gt;years&lt;/a&gt;, bringing to it static types. I believe the same thing is starting to happen in the world of Python, where type checkers like &lt;a href=&quot;http://mypy-lang.org/&quot;&gt;mypy&lt;/a&gt;,  &lt;a href=&quot;https://pyre-check.org/&quot;&gt;Pyre&lt;/a&gt;, and &lt;a href=&quot;https://github.com/Microsoft/pyright&quot;&gt;Pyright&lt;/a&gt; are increasingly used, at least where Python is used by companies to write large systems.&lt;/p&gt;

&lt;p&gt;For the last several releases of Python, there have been an increasing number of type checking features added to each release by various PEPs:&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    Python releases, and related type checking features
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse in&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot; style=&quot;margin-left: 25px;&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
        Python 3.5 - 3.9
          &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot; style=&quot;margin-left: 40px&quot;&gt;
        &lt;ul&gt;
&lt;li&gt;Python 3.5 &lt;small&gt;(Released Sep 2015)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0484/&quot;&gt;Type Hints (PEP 484)&lt;/a&gt; - The original introduction of type checking type annotations into the Python language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.6 &lt;small&gt;(Released Dec 2016)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0526/&quot;&gt;Syntax for variable annotations (PEP 526)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.7 &lt;small&gt;(Released Jun 2018)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0563/#non-typing-usage-of-annotations&quot;&gt;Deferred Evaluation of Annotations with Strings (PEP 563)&lt;/a&gt; - Most type checking annotations no longer need to be in runtime context.&lt;/li&gt;
&lt;li&gt;New kinds of types:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/projects/typeddict/&quot;&gt;TypedDict is available in mypy_extensions&lt;/a&gt; - Typed dictionaries have specific named keys mapped to specific value types. Such dictionaries are ubiquitous in JSON.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0557/#rationale&quot;&gt;Data Classes (PEP 557)&lt;/a&gt; - Data classes are analogous to typed dictionaries.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.8 &lt;small&gt;(Released Oct 2019)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;New kinds of types:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0589/&quot;&gt;TypedDict is standardized (PEP 589)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0586/&quot;&gt;Literal types are standardized (PEP 586)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.9 &lt;small&gt;(Released Oct 2020)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;Fewer imports from the &lt;code&gt;typing&lt;/code&gt; module are needed:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0585/&quot;&gt;Type Hinting Generics In Standard Collections (PEP 585)&lt;/a&gt; - Can use &lt;code&gt;list[T]&lt;/code&gt;, &lt;code&gt;dict[K, V]&lt;/code&gt;, etc in place of &lt;code&gt;List[T]&lt;/code&gt; and &lt;code&gt;Dict[K, V]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


          &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
    &lt;ul&gt;
&lt;li&gt;Python 3.10 &lt;small&gt;(Released Oct 2021)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;New kinds of types:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0612/&quot;&gt;Parameter Specification Variables: &lt;code&gt;ParamSpec&lt;/code&gt; (PEP 612)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0647/&quot;&gt;User-Defined Type Guards: &lt;code&gt;TypeGuard&lt;/code&gt; (PEP 647)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New syntax useful for types:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0613&quot;&gt;Explicit Type Aliases (PEP 613)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0637/&quot;&gt;Support for indexing with keyword arguments (PEP 637)&lt;/a&gt;&lt;/strike&gt; (Rejected 😞)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fewer imports from the &lt;code&gt;typing&lt;/code&gt; module are needed:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0604/&quot;&gt;Union types are shortened to &lt;code&gt;X | Y&lt;/code&gt; (PEP 604)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Optional types shortened to &lt;code&gt;X | None&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0645/&quot;&gt;Optional types shortened to &lt;code&gt;X?&lt;/code&gt; (PEP 645)&lt;/a&gt;&lt;/strike&gt; (&lt;a href=&quot;https://mail.python.org/archives/list/typing-sig@python.org/message/YVEIYEK3H6KPZVYR5NBTXSVJ77WHBXHY/&quot;&gt;Withdrawn&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.11 &lt;small&gt;(Scheduled for Oct 2022)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;New kinds of types:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://peps.python.org/pep-0675/&quot;&gt;Arbitrary Literal String Type (PEP 675)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://peps.python.org/pep-0646/&quot;&gt;Variadic Generics with &lt;code&gt;TypeVarTuple&lt;/code&gt; (PEP 646)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://peps.python.org/pep-0673/&quot;&gt;&lt;code&gt;Self&lt;/code&gt; Type (PEP 673)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;(?) &lt;a href=&quot;https://peps.python.org/pep-0681/&quot;&gt;Data Class Transforms (PEP 681)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New syntax useful for types:

&lt;ul&gt;
&lt;li&gt;&lt;strike&gt;&lt;a href=&quot;https://peps.python.org/pep-0677/&quot;&gt;Callable Type Syntax (PEP 677)&lt;/a&gt;&lt;/strike&gt; (Rejected 😞)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Extensions to existing typing features:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://peps.python.org/pep-0655/&quot;&gt;Required[] and NotRequired[] items for TypedDict (PEP 655)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.12 &lt;small&gt;(Forecasted for Oct 2023)&lt;/small&gt;

&lt;ul&gt;
&lt;li&gt;New kinds of types:

&lt;ul&gt;
&lt;li&gt;(??) &lt;a href=&quot;https://dafoster.net/projects/typeform/&quot;&gt;Type Hint for Runtime Type Annotation Objects: &lt;code&gt;TypeForm&lt;/code&gt;&lt;/a&gt; (planned)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New syntax useful for types:

&lt;ul&gt;
&lt;li&gt;(??) &lt;a href=&quot;https://peps.python.org/pep-0649/&quot;&gt;Deferred Evaluation Of Annotations Using Descriptors (PEP 649)&lt;/a&gt; - Most type checking annotations no longer need to be in runtime context.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The traffic on &lt;a href=&quot;https://mail.python.org/archives/list/typing-sig@python.org/&quot;&gt;typing-sig&lt;/a&gt;, the mailing list where most major new typing features are proposed and designed, has also been seeing increasing traffic year over year.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I personally have found type checking to be very useful when working on large Python applications&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. It helps me find numerous small errors that are introduced during regular development&lt;!-- such as import errors--&gt;. Sure, most of these errors would be caught by the automated tests that I write for each new feature anyway&lt;!-- TODO: footnote+link to TDD or similar practice? --&gt;, but the type checker can find a whole bunch of errors all at once without even running the program, which decreases cycle times when adding new features:&lt;/p&gt;

&lt;p&gt;Without type checking I tend to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a bunch of new code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repeat 4-6 times, in rapid succession:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Run program to manually test.&lt;/li&gt;
&lt;li&gt;Find basic error (like a missing import).&lt;/li&gt;
&lt;li&gt;Fix basic error.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Debug/fix deeper errors in the new code.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;But &lt;em&gt;with&lt;/em&gt; type checking I can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a bunch of new code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run the type checker. Get a report of 4-6 basic errors. Fix basic errors immediately.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Debug/fix deeper errors in the new code.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I appreciate this increased productivity that type checking gives me when working on large programs. And I hope that more Python users try type checking for themselves, especially as Python gains an increasing number of related features in recent releases. It&amp;rsquo;s an exciting time to be a Python developer!&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Discussion&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=25916628&quot;&gt;Hacker News&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2018/04/07/unsound-type-systems-are-still-useful/&quot;&gt;Unsound type systems are still useful&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2019/01/06/dependent-types-impressions-of-a-software-practitioner/&quot;&gt;Dependent Types: Impressions of a software practitioner&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Projects&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/projects/typeddict/&quot;&gt;TypedDict&lt;/a&gt; - Python typechecker support for recognizing structured dictionaries with specific named keys mapped to specific value types.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/projects/trycast/&quot;&gt;trycast&lt;/a&gt; — Parses JSON-like values whose shape is defined by typed dictionaries (TypedDicts) and other standard Python type hints.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Update History&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;2022-03-29:

&lt;ul&gt;
&lt;li&gt;Update final PEPs for Python 3.10, which has now been released.&lt;/li&gt;
&lt;li&gt;Update in-progress PEPs for Python 3.11, which is now in development.&lt;/li&gt;
&lt;li&gt;Update speculative PEPs for Python 3.12, which is in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Increasing traffic on &lt;a href=&quot;https://mail.python.org/archives/list/typing-sig@python.org/&quot;&gt;typing-sig&lt;/a&gt; is reflected in an increasing number of discussions year-over-year. In 2019 there were 63 discussions. In 2020 there were 113 discussions (79% increase). And 2021 is just beginning.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;I personally use type checking in &lt;a href=&quot;/projects/techsmart-platform/&quot;&gt;a large Django web application&lt;/a&gt; that I work on.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2021/01/20/i-no-longer-trust-the-great-suspender</id>
   <title>I no longer trust The Great Suspender</title>
   <published>2021-01-20T00:00:00+00:00</published>
   <updated>2021-01-20T00:00:00+00:00</updated>
   
     <category term="Productivity"/>
   
     <category term="Software"/>
   
     <category term="Offtopic"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2021/01/20/i-no-longer-trust-the-great-suspender/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I know a number of folks use &lt;strong&gt;The Great Suspender&lt;/strong&gt; to automatically suspend
inactive browser tabs in Chrome. Apparently recent versions of this extension
have been &lt;a href=&quot;https://www.reddit.com/r/KyleTaylor/comments/jowlt2/open_source_development_the_great_suspender_saga/&quot;&gt;taken over by a shady anonymous entity&lt;/a&gt; and is now
&lt;a href=&quot;https://www.windowscentral.com/great-suspender-extension-now-flagged-malware-edge-has-built-replacement&quot;&gt;flagged by Microsoft as malware&lt;/a&gt;. Notably the most recent
version of the extension (v7.1.8) has added integrated analytics that can
track all of your browsing activity across all sites. Yikes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendations for users of The Great Suspender (7.1.8):&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;Temporary easy fix&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Disable analytics tracking by opening the extension options for
The Great Suspender and checking the box
&amp;ldquo;Automatic deactivation of any kind of tracking&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Pray that the shady developer doesn&amp;rsquo;t issue a malicious update to The Great Suspender later.
(There&amp;rsquo;s no sensible way to disable updates of an individual extension.)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Permanent harder fix &lt;small&gt;(👈 &lt;strong&gt;Recommended!&lt;/strong&gt;)&lt;/small&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Close as many unneeded tabs as you can.&lt;/li&gt;
&lt;li&gt;Unsuspend all remaining tabs. ⏳

&lt;ul&gt;
&lt;li&gt;⚠️ Any tabs that you forget to unsuspend will be lost
when uninstalling The Great Suspender in the next step.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Uninstall The Great Suspender.&lt;/li&gt;
&lt;li&gt;Download the &lt;a href=&quot;https://github.com/greatsuspender/thegreatsuspender/releases/tag/v7.1.6&quot;&gt;latest good version&lt;/a&gt; of The Great Suspender (7.1.6) from GitHub,
and move it to some permanent location outside your Downloads folder.
(It should be commit 9730c09.)&lt;/li&gt;
&lt;li&gt;Load your downloaded copy as &lt;a href=&quot;https://lifehacker.com/how-you-can-still-download-chrome-extensions-without-us-1826796797&quot;&gt;an unpacked extension&lt;/a&gt;.
(This copy will not auto-update to future untrusted versions of the extension.)&lt;/li&gt;
&lt;li&gt;All done! 🎉&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;s&gt;&lt;strong&gt;Caveat:&lt;/strong&gt; My understanding is that installing an unpacked extension in this way
will cause Chrome to &lt;a href=&quot;https://news.ycombinator.com/item?id=25847171&quot;&gt;issue a new kind of security prompt&lt;/a&gt; every time it is
launched, which you&amp;rsquo;ll have to ignore. 😕&lt;/s&gt;
I see no security prompt for using an unpacked extension at least on
macOS 10.14 Mojave with Chrome 88 and Developer Mode left on.&lt;/p&gt;

&lt;h3&gt;Other options&lt;/h3&gt;

&lt;p&gt;Other browser extensions for suspending tabs exist, as mentioned in the
&lt;a href=&quot;https://news.ycombinator.com/item?id=25846504&quot;&gt;Hacker News discussion&lt;/a&gt; for this article. However I have not conducted my own
security review on any of those other extensions, so buyer beware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2021-02-06 Update:&lt;/strong&gt; Wow. &lt;a href=&quot;https://www.zdnet.com/article/google-kills-the-great-suspender-heres-what-you-should-do-next/&quot;&gt;Google has pulled The Great Suspender&lt;/a&gt; from its web store.
It is still possible to install the latest clean version of The Great Suspender
using the &amp;ldquo;Permanent harder fix&amp;rdquo; instructions above. Or you might consider one
of the &lt;a href=&quot;https://lifehacker.com/ditch-the-great-suspender-before-it-becomes-a-security-1845989664&quot;&gt;alternatives suggested by Lifehacker&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;In &lt;span class=&quot;tag_box tag_box--inline&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&lt;a class=&quot;tag__pill&quot; href=&quot;/articles/topics/#Productivity&quot;&gt;
  Productivity&lt;sup&gt;13&lt;/sup&gt;
&lt;/a&gt;
&lt;a class=&quot;tag__subscribe subscribe&quot; href=&quot;feed://dafoster.net/articles/topics/Productivity.xml&quot;&gt;
  &lt;img src=&quot;/assets/feed-icon-14x14.png&quot; width=&quot;14&quot; height=&quot;14&quot; alt=&quot;Subscribe to Productivity&quot; title=&quot;Subscribe to Productivity&quot;/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2015/03/23/block-distracting-websites/&quot;&gt;Block Distracting Websites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/07/27/sending-email-from-command-line-scripts/&quot;&gt;Sending email from command line scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/10/27/scrivener-an-ide-for-thinkers-creators-and-writers/&quot;&gt;Scrivener: An IDE for thinkers, creators, and writers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In &lt;span class=&quot;tag_box tag_box--inline&quot;&gt;&lt;span class=&quot;tag&quot;&gt;&lt;a class=&quot;tag__pill&quot; href=&quot;/articles/topics/#Software&quot;&gt;
  Software&lt;sup&gt;78&lt;/sup&gt;
&lt;/a&gt;
&lt;a class=&quot;tag__subscribe subscribe&quot; href=&quot;feed://dafoster.net/articles/topics/Software.xml&quot;&gt;
  &lt;img src=&quot;/assets/feed-icon-14x14.png&quot; width=&quot;14&quot; height=&quot;14&quot; alt=&quot;Subscribe to Software&quot; title=&quot;Subscribe to Software&quot;/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2017/03/25/how-to-design-large-programs-with-abstraction-and-encapsulation/&quot;&gt;How to Design Large Programs with Abstraction and Encapsulation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2019/06/27/os-abstractions-are-failing-us</id>
   <title>OS Abstractions are Failing Us</title>
   <published>2019-06-27T00:00:00+00:00</published>
   <updated>2019-06-27T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2019/06/27/os-abstractions-are-failing-us/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;In recent years I&amp;rsquo;ve increasingly noticed software being written that cannot get the performance it needs unless it bypasses usual operating system services.&lt;/p&gt;

&lt;h2&gt;Concurrency&lt;/h2&gt;

&lt;p&gt;For example let&amp;rsquo;s consider a program that wants to do many tasks at the same time. Traditionally you would either create multiple &lt;strong&gt;threads&lt;/strong&gt; or multiple &lt;strong&gt;processes&lt;/strong&gt; for each parallel line of execution. But threads and processes have a lot of overhead - in particular they take up a lot of memory - so it&amp;rsquo;s unwise to have more than a few hundred of them. So if you have a web service handling hundreds or thousands of connections per second, you cannot effectively serve all those requests on one machine using a thread or process per connection.&lt;/p&gt;

&lt;p&gt;So some developers turn to writing their web servers with asynchronous I/O and &lt;strong&gt;green threads&lt;/strong&gt; so that they can multiplex multiple concurrent tasks onto a single OS thread. You can run millions of these green threads concurrently per machine on modern hardware. That&amp;rsquo;s pretty slick, at least until one of those green threads starts hogging the CPU or accidentally performs a blocking operation. Such a misbehaving green thread will block all other green threads from running, since they use cooperative multitasking and cannot be preempted.&lt;/p&gt;

&lt;p&gt;Other developers turn to &lt;strong&gt;microthreads&lt;/strong&gt; in languages like Go, Erlang, or Elixir&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. These environments have an in-process scheduler that multiplexes microthreads onto a single OS thread. Again you can run millions of microthreads concurrently on modern hardware. Happily microthreads &lt;em&gt;can&lt;/em&gt; be preempted by the scheduler and so a misbehaving microthread won&amp;rsquo;t interfere with other microthreads, although it may cause your server to burn CPU wastefully.&lt;/p&gt;

&lt;h2&gt;Disk I/O throughput&lt;/h2&gt;

&lt;p&gt;These days our disks are solid-state drives with access times similar to RAM rather than the slower rotating magnetic platters of earlier years. Yet my understanding is that the common filesystem and socket abstractions require per-operation overhead comparable to the time spent actually performing the I/O. Yikes. Research seems to be underway considering ways to bypass various OS abstractions to get faster results.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;Exciting times&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s neat to be working in computing at the time when some of the fundamental abstractions are being called into question. When practitioners are receptive to change there&amp;rsquo;s an opportunity to contribute new ideas and actually have them tried and used.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/JvBT4XBdoUE?t=358&quot;&gt;The Soul of Erlang and Elixir - Saša Jurić&lt;/a&gt;&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://penberg.org/parakernel-hotos19.pdf&quot;&gt;I/O Is Faster Than the CPU – Let&amp;rsquo;s Partition Resources and Eliminate (Most) OS Abstractions&lt;/a&gt;&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2019/01/06/dependent-types-impressions-of-a-software-practitioner</id>
   <title>Dependent Types: Impressions of a software practitioner</title>
   <published>2019-01-06T00:00:00+00:00</published>
   <updated>2019-01-06T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2019/01/06/dependent-types-impressions-of-a-software-practitioner/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;img class=&quot;img-box-right img-200&quot; alt=&quot;Book: The Little Typer&quot; src=&quot;/assets/2019/the-little-typer.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Dependent types are a feature of certain programming language type systems that are unusually powerful, expressive, and precise, compared with other kinds of types. Dependently-typed programming languages such as Coq, Agda, and Idris appear occasionally in academia but not at all in mainstream languages used by software practitioners.&lt;/p&gt;

&lt;p&gt;I have been curious about dependent types for some time because of their potential for writing programs that are more correct and have fewer bugs. If you look at my &lt;a href=&quot;/articles/2014/12/20/languages-by-hardware-distance/&quot;&gt;hierarchy of programming languages&lt;/a&gt; you&amp;rsquo;ll notice dependently typed languages way at the bottom beyond even the &amp;ldquo;high-typed languages&amp;rdquo;. I even wrote &lt;a href=&quot;https://github.com/davidfstr/idris-insertion-sort&quot;&gt;a provably-correct implementation of insertion sort&lt;/a&gt; in Idris a few years ago.&lt;/p&gt;

&lt;p&gt;Recently my interest in dependent types was rekindled by the release of a new book, &lt;a href=&quot;https://www.amazon.com/Little-Typer-MIT-Press/dp/0262536439/&quot;&gt;The Little Typer&lt;/a&gt;, that aims to be an accessible introduction to dependently typed programming. I just finished reading that book. Below are my impressions of the applicability of dependent types to a software practitioner such as myself.&lt;/p&gt;

&lt;h2&gt;What is a dependent type anyway?&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;type&lt;/strong&gt; describes the shape of a particular value or the shape of a variable that holds values. Being able to talk about the shape of something in a programming language is useful because most kind of operations always want to be given things of the same shape.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;simple types&lt;/strong&gt; like &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, and &lt;code&gt;List&lt;/code&gt; in all typed languages.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;generic types&lt;/strong&gt; like &lt;code&gt;List of Integer&lt;/code&gt; and &lt;code&gt;Map of String to Integer&lt;/code&gt; that are defined in terms of other &lt;em&gt;types&lt;/em&gt;. Generic types are extremely useful for describing collection values (i.e. lists, sets, maps, etc), which are pervasive in programming.&lt;/p&gt;

&lt;p&gt;Then there are &lt;strong&gt;dependent types&lt;/strong&gt; like &lt;code&gt;List of Integer of length 5&lt;/code&gt; or &lt;code&gt;IsSorted [1,2,3]&lt;/code&gt; that are defined in terms of &lt;em&gt;values&lt;/em&gt;.  Since values are more precise things than types, a dependent type (defined with a value as a parameter) is a more precise shape than a simple unparameterized type or a generic type (defined with a type as a parameter).&lt;/p&gt;

&lt;h2&gt;What are dependent types useful for?&lt;/h2&gt;

&lt;h3&gt;More precise types in general&lt;/h3&gt;

&lt;p&gt;Since dependent types allow defining more precise shapes than other kinds of types, and because type systems can be used by a type checker to verify the consistency of a program, dependent types allow defining functions in a program with more precise input and output restrictions that are automatically checked for correctness by the type checker. Such automatic checking is powerful for providing confidence that the program is correct (i.e. self-consistent).&lt;/p&gt;

&lt;p&gt;With dependent types, you can define a known-length collection type such as &lt;code&gt;List of Integer of length 5&lt;/code&gt;. This is clearly more precise than &lt;code&gt;List of Integer&lt;/code&gt; or &lt;code&gt;List&lt;/code&gt;. However I don&amp;rsquo;t think this additional precision is generally &lt;em&gt;useful&lt;/em&gt;: very few functions in my programs care about how long their lists are at compile type. At most some functions would prefer to disallow empty lists.&lt;/p&gt;

&lt;p&gt;With the known-length collection type mentioned above, you can further define a function &lt;code&gt;first&lt;/code&gt; that takes a &lt;em&gt;non-empty&lt;/em&gt; list of values (that the type checker can verify as definitely non-empty) and can guarantee that it will return an output value without having any kind of error. In most languages the best you can do is define such a function that takes any list that will fail at runtime if it is given an empty list. With dependent types you can flag such uses at compile time.&lt;/p&gt;

&lt;h3&gt;Proofs; Propositions as types&lt;/h3&gt;

&lt;p&gt;Dependent types allow you to construct &lt;a href=&quot;/articles/2015/02/27/proof-terms-in-idris/&quot;&gt;&lt;strong&gt;proof types&lt;/strong&gt;&lt;/a&gt; such as &lt;code&gt;(IsPositive 5)&lt;/code&gt; and their associated proof values. The ability to write arbitrary logical statements as types in a dependently typed programming language is sometimes called &amp;ldquo;propositions as types&amp;rdquo;. This capability is particularly useful for human mathematicians, theorem provers, and academics.&lt;/p&gt;

&lt;p&gt;It can be useful to use proof types to write functions that not only compute something useful but also return a proof that they calculated the &lt;em&gt;correct&lt;/em&gt; value. For example it is possible to write &lt;a href=&quot;https://github.com/davidfstr/idris-insertion-sort&quot;&gt;a sorting function that is proven correct&lt;/a&gt; in that it returns not only an output sorted list but also a proof that the output list is sorted and also a proof that the output list has the same elements as the input list. That&amp;rsquo;s pretty cool. Unfortunately these proof values can be devilishly difficult to construct and manipulate.&lt;/p&gt;

&lt;h3&gt;That&amp;rsquo;s it?&lt;/h3&gt;

&lt;p&gt;These are all the applications I&amp;rsquo;ve been able to discover for dependent types so far. In particular I haven&amp;rsquo;t been able to find any specific &amp;ldquo;killer application&amp;rdquo; of dependent types to any common problem that I see as a software practitioner.&lt;/p&gt;

&lt;h2&gt;What costs arise from using dependent types?&lt;/h2&gt;

&lt;h3&gt;Complexity&lt;/h3&gt;

&lt;p&gt;You must learn, remember, and understand several new kinds of language constructs to manipulate dependent types. In particular in addition to regular function application (λ) you must also learn about how to construct and manipulate dependent pairs using Π and Σ. This creates a &lt;strong&gt;steeper initial learning curve&lt;/strong&gt; and &lt;strong&gt;constant mental overhead&lt;/strong&gt; while writing dependently-typed programs.&lt;/p&gt;

&lt;h3&gt;Verbosity&lt;/h3&gt;

&lt;p&gt;Dependent types have additional parameters that need to be passed between functions, transformed inside functions, and output by functions. Thus any function manipulating a dependently typed value will require &lt;strong&gt;a lot more code&lt;/strong&gt; to manipulate these additional parameters than an equivalent function using simpler-typed values will not.&lt;/p&gt;

&lt;p&gt;More code takes longer to write, provides more opportunities for introducing bugs, and is more time-consuming to maintain.&lt;/p&gt;

&lt;h3&gt;Lack of encapsulation&lt;/h3&gt;

&lt;p&gt;Using dependent types frequently seems to involve &lt;strong&gt;pattern matching on the low-level structure of values&lt;/strong&gt;. For example it is common for a function manipulating the natural number type (&lt;code&gt;Nat&lt;/code&gt;) to pattern-match on the specific value constructors of &lt;code&gt;Nat&lt;/code&gt;, revealing that it is implementated as a &lt;code&gt;0&lt;/code&gt; base value wrapped inside some number of &lt;code&gt;add1&lt;/code&gt;s, similar to a linked list.&lt;/p&gt;

&lt;p&gt;If you wanted to change the natural number type to instead be implemented using a more-efficient list of bits, you wouldn&amp;rsquo;t be able to do so without breaking every function using the original definition of natural numbers.&lt;/p&gt;

&lt;h3&gt;Restrictions on loops and recursion&lt;/h3&gt;

&lt;p&gt;Several dependently-typed languages I&amp;rsquo;ve encountered so far (at least Pie and Agda) disallow function definitions that cannot be proven by the compiler to always terminate, presumably to guard against the type checker going into an infinite loop if presented with a problematic program. In particular this means &lt;strong&gt;no generalized loops&lt;/strong&gt; and &lt;strong&gt;no generalized recursion&lt;/strong&gt; are allowed. These language constructs are extremely useful and it is frequently a pain to work around their absence.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There are no killer apps of dependent types that I can identify for software practitioners, and dependent types have significant costs. Thus in general I feel the costs of using dependent types outweigh the benefits for practical software applications outside the domain of theorem-proving.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2015/02/27/proof-terms-in-idris/&quot;&gt;Proof terms in Idris&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/02/17/agda-second-impressions/&quot;&gt;Agda: Second Impressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/01/24/agda-notes-and-evaluation/&quot;&gt;Agda: First Impressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2018/04/07/unsound-type-systems-are-still-useful/&quot;&gt;Unsound type systems are still useful&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2018/11/24/why-isnt-the-external-link-symbol-in-unicode</id>
   <title>Why isn't the external link symbol in Unicode?</title>
   <published>2018-11-24T00:00:00+00:00</published>
   <updated>2018-11-24T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2018/11/24/why-isnt-the-external-link-symbol-in-unicode/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I have frequently wanted to use the external link symbol ( &lt;img src=&quot;/assets/2018/external_link.png&quot; alt=&quot;external link&quot; /&gt; ) in text that I&amp;rsquo;m writing, without having to resort to including an image. Normally the solution there would be to find the graphical symbol in Unicode and figure out how to type it.&lt;/p&gt;

&lt;p&gt;Apparently at least one &lt;a href=&quot;https://www.unicode.org/L2/L2006/06268-ext-link.pdf&quot;&gt;proposal&lt;/a&gt; for the external link symbol was submitted to the Unicode Consortium as far back as August 2006. It was reviewed at a meeting on November 2006 and it was decided to post a &lt;a href=&quot;https://www.unicode.org/L2/L2006/06324.htm#109-C26&quot;&gt;public review&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Later in April 2012 someone noticed that the public review had never been posted because the symbols subcomittee (which was tasked with posting the review) had been folded into the Unicode Technical Committee group and that task had gotten &lt;a href=&quot;https://www.unicode.org/L2/L2012/12143-ext-link.html&quot;&gt;lost in the shuffle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then in June 2012 that proposal was finally &lt;a href=&quot;https://www.unicode.org/alloc/nonapprovals.html&quot;&gt;rejected&lt;/a&gt; on the following basis:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;2012-2, EXTERNAL LINK SIGN, 2012-June-06&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Proposals to encode a character for the &amp;ldquo;external link sign&amp;rdquo;, which is often seen as a graphic element indicating a link to a document located external to the website where the page using the external link sign resides. (See L2/06-268, L2/12-143, L2/12-169.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disposition&lt;/strong&gt;: The UTC rejected the proposals to add &amp;ldquo;external link sign&amp;rdquo;, most recently in L2/12-169. It is unclear that the entity in question is actually an element of plain text, given the inevitable connection to its function in linking to other documents, and thus its coexistence with markup for links. Furthermore, the existing widespread practice of representing this sign on web pages using images (often specified via CSS styles) would be unlikely to benefit from attempting to encode a character for this image. (This notice of non-approval should not be construed as precluding alternate proposals which might propose encoding a simple shape-based symbol or symbols similar in appearance to the images used for external link signs, should an appropriate plain-text argument for the need to encode such a simple graphic symbol be forthcoming.) References to UTC Minutes: [131-C26], May 10, 2012.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I find this rejection disappointing.&lt;/p&gt;

&lt;p&gt;Its main rationale appears to be that the external link icon is not an element of plain text. I would agree that is the case. However I would like to point out that emoji and other similar useful symbols are not plain text either yet they have been accepted and continue to be accepted.&lt;/p&gt;

&lt;p&gt;I wonder if the external link symbol would be accepted as an emoji? I don&amp;rsquo;t have enough energy right now to pursue that myself.&lt;/p&gt;

&lt;!-- Also of interest: The rationale for rejecting the external link symbol discouraged another person from even submitting the feed symbol for consideration: https://jameshfisher.com/2017/09/29/unicode-is-only-for-plaintext.html --&gt;


&lt;p&gt;&lt;strong&gt;2021 Update:&lt;/strong&gt; These days I use the ⎋ symbol to approximate the external link
symbol in my own informal writing. I&amp;rsquo;ve also used 🔗 in the past.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2018/09/23/the-flat-module-pattern-in-javascript</id>
   <title>The Flat Module Pattern in JavaScript</title>
   <published>2018-09-23T00:00:00+00:00</published>
   <updated>2018-09-23T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2018/09/23/the-flat-module-pattern-in-javascript/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;There are several patterns for structuring modules in JavaScript. The most common ones I see talked about is the original &lt;a href=&quot;http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html&quot;&gt;JavaScript Module Pattern&lt;/a&gt;, &lt;a href=&quot;https://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailamd&quot;&gt;AMD Modules&lt;/a&gt;, &lt;a href=&quot;https://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailcommonjs&quot;&gt;CommonJS Modules&lt;/a&gt;, and the emerging &lt;a href=&quot;https://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailharmony&quot;&gt;Harmony Modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The large JavaScript application that I work on at work - an in-browser IDE - does not presently use any of these well-known patterns but instead uses what I&amp;rsquo;m going to call the &lt;strong&gt;Flat Module Pattern&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;The Flat Module Pattern&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s what the Flat Module Pattern looks like, for an excerpt of a real module called &lt;code&gt;save.js&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/*public*/ function setupSave() {
    if (isMainOrStandaloneWindow()) {
        setupSaveToken();
    }
}

// -----------------------------------------------------------------------------
// Autosave

var DELAY_AFTER_TYPING_STOPS_TO_AUTOSAVE = 2000;

/*public*/ function autosave(fileInfo) {
    ...
}

// -----------------------------------------------------------------------------
// Save Token

function setupSaveToken() {
    ...
}

/*public*/ function isUnsafeToSave() {
    ...
}

// -----------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only function and constant declarations exist at the top-level. No other executable code may run at the top-level.&lt;/li&gt;
&lt;li&gt;Public functions are marked with the keyword-comment &lt;code&gt;/*public*/&lt;/code&gt;. A module should not attempt to reference a non-public method in a different module.&lt;/li&gt;
&lt;li&gt;Modules do not import each other or declare cross-module dependencies explicitly.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Consequences of this pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modules can be &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;-included in any order, since there are no side-effects of including a module.&lt;/li&gt;
&lt;li&gt;All functions are dumped into the global namespace.

&lt;ul&gt;
&lt;li&gt;In practice this is not a problem since well-named application functions have distinct names from other application functions, and libraries don&amp;rsquo;t generally dump functions directly into the global namespace.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;All such modules on a particular page are directly included by the HTML page:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{% compress js %}
    &amp;lt;!-- Library --&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/student_survey.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/util/dialog.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/util/markdown.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/util/slider.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/util/url.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/util/websocket.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/vendor/jquery.min.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'tsk_platform/vendor/mdl/material.min.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;

    &amp;lt;!-- Page-Specific --&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/__init__.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/__init__.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/assignment/__init__.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/assignment/code_comprehension.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/assignment/code_writing.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/code_instructions.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/project.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/panels/slides.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/run/__init__.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/run/engine/java.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/run/engine/python.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/run/run_window.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/__init__.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/editor/blocks.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/editor/font.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/editor/image.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/editor/scene.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/editor/sound.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/editor/text.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;{% static 'ide/code/tabs/save.js' %}&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
        setupCodePage();
    &amp;lt;/script&amp;gt;
{% endcompress %}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In considering how modules may reference members of each other:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page-specific modules may freely reference members from each other and from library modules.&lt;/li&gt;
&lt;li&gt;Most library modules are self-contained and do not reference members from anybody, although some library modules may reference members from other library modules.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The Flat Module Pattern is incredibly simple to follow, with almost no boilerplate. It is also easy to concatenate and minify.&lt;/p&gt;

&lt;p&gt;My team has been using this pattern successfully over the last 4 years or so with a codebase that is now approximately 55,000 lines of JavaScript. I&amp;rsquo;m pretty happy with it.&lt;/p&gt;

&lt;h2&gt;The Encapsulated Flat Module Pattern&lt;/h2&gt;

&lt;p&gt;The one major drawback of the above Flat Module Pattern is that public functions are advisory-only since they are just marked with &lt;code&gt;/*public*/&lt;/code&gt; comments. It is still possible (and easy) to accidentally improperly reference a non-public function from outside the module it is declared in.&lt;/p&gt;

&lt;p&gt;So here&amp;rsquo;s an enhanced variation I call the &lt;strong&gt;Encapsulated Flat Module Pattern&lt;/strong&gt; that doesn&amp;rsquo;t have that problem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(function() {
    function public(func) { window[func.name] = func; }

    public(function setupSave() {
        if (isMainOrStandaloneWindow()) {
            setupSaveToken();
        }
    });

    // -----------------------------------------------------------------------------
    // Autosave

    var DELAY_AFTER_TYPING_STOPS_TO_AUTOSAVE = 2000;

    public(function autosave(fileInfo) {
        ...
    });

    // -----------------------------------------------------------------------------
    // Save Token

    function setupSaveToken() {
        ...
    }

    public(function isUnsafeToSave() {
        ...
    });

    // -----------------------------------------------------------------------------
})();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that each &lt;code&gt;/*public*/&lt;/code&gt; advisory comment has been replaced with a call to a special &lt;code&gt;public(...)&lt;/code&gt; function that actually exports the provided function. Any function that is not marked as public is truly private and not available for reference by other modules.&lt;/p&gt;

&lt;p&gt;Benefits of this pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public functions are easy to distinguish from private functions at their definition site.&lt;/li&gt;
&lt;li&gt;Public functions and private functions can be freely interleaved. In particular there is no need to group public functions in the module together.&lt;/li&gt;
&lt;li&gt;Public and private functions in the same module can call each other naturally and with the same syntax. In particular public functions do not have a special calling convention.&lt;/li&gt;
&lt;li&gt;No function names are duplicated by the boilerplate. In particular there&amp;rsquo;s no need to repeat function names in a public exports list, as is common with other JavaScript module patterns.&lt;/li&gt;
&lt;li&gt;It is easy to convert a function from private to public or visa-versa. In particular no references need to be updated since public and private functions are referenced the same way.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve found these JavaScript module patterns to be very useful in structuring JavaScript application code I&amp;rsquo;ve written over the last few years.&lt;/p&gt;

&lt;p&gt;I think these patterns would work well in any large JavaScript application that avoids class inheritance&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and has reasonable non-colliding public function names.&lt;/p&gt;

&lt;p&gt;I do &lt;em&gt;not&lt;/em&gt; think these patterns would be a good idea for JavaScript &lt;em&gt;libraries&lt;/em&gt; that need to avoid polluting the global namespace. For such libraries, falling back on the &lt;a href=&quot;https://github.com/umdjs/umd&quot;&gt;Universal Module Definition&lt;/a&gt; pattern seems more prudent.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Supporting class inheritance requires serializing the order of top-level definitions since the definition of a subclass depends of the definition of its superclass, and therefore subclasses must be declared &lt;em&gt;after&lt;/em&gt; its related superclass. The module patterns in this article do not serialize top-level definition order and therefore cannot reliably support subclasses being declared in a different module than its superclass.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2018/06/02/performance-testing</id>
   <title>Performance Testing</title>
   <published>2018-06-02T00:00:00+00:00</published>
   <updated>2022-02-06T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Django"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2018/06/02/performance-testing/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;In this article I will describe the theory of &lt;strong&gt;performance testing&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and how we conduct such testing in practice at my company TechSmart, in the context of rich web applications and web services.&lt;/p&gt;

&lt;p&gt;By the end of this article you should understand how we define performance testing and perhaps get some ideas for implementing or customizing your own tools for performance-testing your own web service.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#theory&quot;&gt;Theory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#gatling-concepts&quot;&gt;Gatling Concepts&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#scenarios-and-simulations&quot;&gt;Scenarios and simulations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#simulation-parameters&quot;&gt;Simulation parameters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#load-generation&quot;&gt;Load generation&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#the-gatling-management-command&quot;&gt;The &amp;ldquo;gatling&amp;rdquo; management command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pt-run&quot;&gt;The &amp;ldquo;perftest run&amp;rdquo; management command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#targeting-remote-environments&quot;&gt;Targeting remote environments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#stress-testing&quot;&gt;Stress testing&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#pt-maxload&quot;&gt;The &amp;ldquo;perftest maxload&amp;rdquo; management command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#bottleneck-isolation&quot;&gt;Bottleneck isolation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#overload-behavior&quot;&gt;Overload behavior&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#end&quot;&gt;End&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;theory&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Theory&lt;/h2&gt;

&lt;p&gt;Performance testing of a web service typically involves verifying non-functional requirements such as whether it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Responsive&lt;/strong&gt; - responds quickly to requests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resilient&lt;/strong&gt; - handles a large number of requests; avoids crashing outright; rejects or queues requests as needed if too many in progress at once&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault-Tolerant&lt;/strong&gt; - whether the service self-heals if it crashes&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Performance testing aims to answer the following kinds of questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How responsive is the service under a particular amount of load?&lt;br/&gt;
(See &lt;a href=&quot;#pt-run&quot;&gt;§ &amp;ldquo;perftest run&amp;rdquo;&lt;/a&gt; below)&lt;/li&gt;
&lt;li&gt;What is the maximum load that the service can handle?&lt;br/&gt;
(See &lt;a href=&quot;#pt-maxload&quot;&gt;§ &amp;ldquo;perftest maxload&amp;rdquo;&lt;/a&gt; below)&lt;/li&gt;
&lt;li&gt;How responsive is the service under its maximum load?&lt;/li&gt;
&lt;li&gt;What is the bottleneck that is saturated when the service is at its maximum load?&lt;br/&gt;
(See &lt;a href=&quot;#bottleneck-isolation&quot;&gt;§ &amp;ldquo;Bottleneck isolation&amp;rdquo;&lt;/a&gt; below)&lt;/li&gt;
&lt;li&gt;How does the service behave when stressed beyond its maximum load?&lt;br/&gt;
(See &lt;a href=&quot;#overload-behavior&quot;&gt;§ &amp;ldquo;Overload behavior&amp;rdquo;&lt;/a&gt; below)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The core of performance testing is &lt;strong&gt;load generation&lt;/strong&gt;. You write a program that generates a specified amount of load on your target web service and measure what happens when various amounts of load are applied.&lt;/p&gt;

&lt;p&gt;There are many load generation tools that exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One of the oldest load generation tools is &lt;a href=&quot;https://jmeter.apache.org/&quot;&gt;JMeter&lt;/a&gt;, which uses a GUI to define simulation programs in an XML-based file format. JMeter uses a separate OS thread for each concurrent HTTP connection which severely limits the number of concurrent HTTP connections it can host on a single box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At my company TechSmart we use &lt;a href=&quot;http://gatling.io&quot;&gt;Gatling&lt;/a&gt; as our load generation tool. Compared with JMeter, Gatling is far more efficient at generating load because it uses multiplexed async I/O on a single OS thread to handle all HTTP connections. Also, Gatling simulations are written in an actual programming language (Scala) rather than XML, so you can write your simulations with rich abstractions and do more-advanced customizations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;gatling-concepts&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Gatling Concepts&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;scenarios-and-simulations&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Scenarios and simulations&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;scenario&lt;/strong&gt; describes a pattern of HTTP requests that a single user makes against a web service. For example in the &lt;code&gt;ViewCodePage&lt;/code&gt; scenario a user performs the {&lt;code&gt;LoginPage.loginWithoutRedirect&lt;/code&gt;, &lt;code&gt;CodePage.view&lt;/code&gt;} subscenarios which consist of individual HTTP requests.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;simulation&lt;/strong&gt; describes an aggregate pattern of HTTP requests that &lt;em&gt;multiple&lt;/em&gt; users make against a web service. For example the &lt;code&gt;ViewCodePage(X, Y)&lt;/code&gt; simulation simulates X users arriving over Y seconds that each perform the actions described in the &lt;code&gt;ViewCodePage&lt;/code&gt; scenario.&lt;/p&gt;

&lt;p&gt;At TechSmart we have written several simulations that exercise each of the major pages on our platform website.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;simulation-parameters&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Simulation parameters&lt;/h3&gt;

&lt;p&gt;Most simulations written at TechSmart vary their behavior based on &lt;em&gt;parameters&lt;/em&gt; that are passed in as environment variables. Simulations read these environment variables upon initialization using code like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class LoginAsStudent extends Simulation {
    val X = sys.env.getOrElse(&quot;X&quot;, &quot;__missing__&quot;).toInt
    val Y = sys.env.getOrElse(&quot;Y&quot;, &quot;__missing__&quot;).toInt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thus the set of parameters that a particular simulation expects can be deduced by reading the top of the simulation&amp;rsquo;s source code.&lt;/p&gt;

&lt;p&gt;Most simulations at TechSmart support X and Y parameters to inject X users over Y seconds during the simulation.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;load-generation&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Load generation&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;the-gatling-management-command&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;The &amp;ldquo;gatling&amp;rdquo; management command&lt;/h3&gt;

&lt;p&gt;The &amp;ldquo;gatling&amp;rdquo; management command is a low-level command we&amp;rsquo;ve implemented at TechSmart that invokes the Gatling tool, sets up various required paths automatically, and runs a Gatling simulation script.&lt;/p&gt;

&lt;p&gt;A typical invocation of the &amp;ldquo;gatling&amp;rdquo; management command looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ X=4 Y=1 pm gatling --simulation tsplatform.LoginAsStudent
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;&lt;p&gt;Note: The &lt;code&gt;pm&lt;/code&gt; command above is an alias for &lt;code&gt;python3 manage.py&lt;/code&gt; which is the Django task runner.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This invocation is equivalent to the more-verbose:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ X=4 Y=1 $GATLING_HOME/bin/gatling.sh --simulation tsplatform.LoginAsStudent --simulations-folder $PERFORMANCE_HOME/simulations --data-folder $PERFORMANCE_HOME/data --bodies-folder $PERFORMANCE_HOME/bodies
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Gatling tool emits lots of output in the console while it is running and eventually generates an HTML report with detailed statistics about what HTTP requests were made during the simulation, response times for individual and aggregated requests, and other information.&lt;/p&gt;

&lt;!-- TODO: Include an image of a typical Gatling report --&gt;


&lt;p&gt;&lt;a name=&quot;pt-run&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;The &amp;ldquo;perftest run&amp;rdquo; management command&lt;/h3&gt;

&lt;p&gt;Typically the most important information in the Gatling HTML report generated by running a simulation is the &lt;strong&gt;maximum response time&lt;/strong&gt;&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; for a particular type of HTTP request that was made during the simulation. &lt;!-- For example the `ViewCodePage(X, Y)` simulation makes many HTTP requests of type {`view_login`, `submit_login`, and `view_code`} but we only care about the maximum response time of the `view_code` requests. --&gt;&lt;/p&gt;

&lt;p&gt;Consequently we&amp;rsquo;ve created a &amp;ldquo;perftest run&amp;rdquo; management command that behaves similarly to the &amp;ldquo;gatling&amp;rdquo; command but automatically presents the maximum response time for the most important request type&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; after running the simulation.&lt;/p&gt;

&lt;p&gt;With the &amp;ldquo;perftest run&amp;rdquo; management command, we can easily answer the question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How responsive is the service under a particular amount of load?

&lt;ul&gt;
&lt;li&gt;When R requests/second are made continuously, for some R = X/Y:

&lt;ul&gt;
&lt;li&gt;What is the maximum response time?&lt;/li&gt;
&lt;li&gt;What does the response time distribution look like?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here is an example of running a simple simulation, using &amp;ldquo;perftest setup&amp;rdquo; to create test data and then using &amp;ldquo;perftest run&amp;rdquo; to get the maximum response time for a particular amount of load:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ pm perftest setup students 8
Deleting test students...
Creating 8 test student(s)...

$ pm perftest setup calendars 1
Deleting test calendars...
Creating 1 test calendar(s)...
Associating 8 user(s) with 1 calendar(s)...

$ pm perftest run LoginAsStudent 4 1
Running simulation with 4 user(s) over 1 second(s)...
When 4 user(s) over 1 second(s), max response time for request 'submit_login' is 393 ms.
  Report: /Users/me/pkgs/gatling-charts-highcharts-bundle-2.2.2/results/loginasstudent-1497049484195/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(We also have a &amp;ldquo;perftest teardown&amp;rdquo; command that deletes all test data created by &amp;ldquo;perftest setup&amp;rdquo;.)&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;targeting-remote-environments&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Targeting remote environments&lt;/h3&gt;

&lt;p&gt;Our simulations are written by default to target the website running on the developer&amp;rsquo;s local machine (127.0.0.1). For real testing you&amp;rsquo;ll want to run tests on a remote version of the website such as the one on a dedicated perf environment (perf.example.com).&lt;/p&gt;

&lt;p&gt;For example, to run a command on our performance environment we would first setup the environment with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ pm on perf perftest setup students 8
$ pm on perf perftest setup calendars 1
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;&lt;p&gt;Note: The &amp;ldquo;on&amp;rdquo; management command runs some other command in the context of a particular remote environment.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;And then we&amp;rsquo;d run the performance test by typing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ pm on perf perftest run LoginAsStudent 4 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &amp;ldquo;on&amp;rdquo; command sets the &lt;code&gt;GATLING_BASE_URL&lt;/code&gt; environment variable (among other things) and the &amp;ldquo;perftest run&amp;rdquo; subcommand passes that environment variable to the underlying Gatling simulation. The &lt;code&gt;GATLING_BASE_URL&lt;/code&gt; variable specifies the base URL that all HTTP requests are prefixed with. For example the above command is equivalent to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ # (Change environment to &quot;perf&quot;, defaulting to its database tier, cache tier, etc)
$ X=4 Y=1 GATLING_BASE_URL=http://perf.example.com pm gatling --simulation tsplatform.LoginAsStudent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All simulations support the &lt;code&gt;GATLING_BASE_URL&lt;/code&gt; parameter to change the base URL because they all use a common Gatling HTTP Protocol object that defines its base URL from &lt;code&gt;GATLING_BASE_URL&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class LoginAsStudent extends Simulation {
    ...
    val httpProtocol = Common.httpProtocol
    ...
}

object Common {
    private val baseUrl = sys.env.getOrElse(
        &quot;GATLING_BASE_URL&quot;, &quot;http://127.0.0.1:8000&quot;)

    val httpProtocol = http
        .baseURL(baseUrl)
        ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a id=&quot;stress-testing&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Stress testing&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;pt-maxload&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;The &amp;ldquo;perftest maxload&amp;rdquo; management command&lt;/h3&gt;

&lt;p&gt;The &amp;ldquo;perftest maxload&amp;rdquo; management command can be used to automatically perform &amp;ldquo;perftest run&amp;rdquo; several times to determine the maximum number of users (X) over a given period of time (Y) such that the maximum response time for the HTTP request of interest is less than a particular threshold (1,200 ms by default).&lt;/p&gt;

&lt;p&gt;With the &amp;ldquo;perftest maxload&amp;rdquo; management command, we can answer the questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the maximum load that the service can handle?

&lt;ul&gt;
&lt;li&gt;What is the maximum requests/second that can be made before the requests start backing up and response times go hockeystick?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How responsive is the service under its maximum load?&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;An example invocation of &amp;ldquo;perftest maxload&amp;rdquo; looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ pm perftest maxload LoginAsStudent --preserve-calendars
Determining baseline response time...

Deleting test students...
Creating 1 test student(s)...
Associating 1 user(s) with 1 calendar(s)...
Running simulation with 1 user(s) over 5 second(s)...
When 1 user(s) over 5 second(s), max response time for request 'submit_login' is 138 ms.
  Report: /Users/davidf/pkgs/gatling-charts-highcharts-bundle-2.2.2/results/loginasstudent-1497567171908/index.html

Seeking shaft of hockeystick...

Deleting test students...
Creating 2 test student(s)...
Associating 2 user(s) with 1 calendar(s)...
Running simulation with 2 user(s) over 5 second(s)...
When 2 user(s) over 5 second(s), max response time for request 'submit_login' is 124 ms.
  Report: /Users/davidf/pkgs/gatling-charts-highcharts-bundle-2.2.2/results/loginasstudent-1497567182571/index.html

(... ditto for 4 users over 5 seconds ... OK ...)
(... ditto for 8 users over 5 seconds ... OK ...)
(... ditto for 16 users over 5 seconds ... OK ...)
(... ditto for 32 users over 5 seconds ... OK ...)
(... ditto for 64 users over 5 seconds ... OK ...)
(... ditto for 128 users over 5 seconds ... FAIL ...)

Seeking knee of hockeystick... About 6 step(s) or 1:41.

Deleting test students...
Creating 96 test student(s)...
Associating 96 user(s) with 1 calendar(s)...
Running simulation with 96 user(s) over 5 second(s)...
When 96 user(s) over 5 second(s), max response time for request 'submit_login' is 3754 ms.
  Report: /Users/davidf/pkgs/gatling-charts-highcharts-bundle-2.2.2/results/loginasstudent-1497567312703/index.html

(... ditto several times, performing a binary search ...)

num_users,response_time,num_seconds
1,138,5
2,124,5
4,120,5
8,157,5
16,123,5
32,182,5
64,920,5
128,6844,5
96,3754,5
80,2407,5
72,1449,5
68,1227,5
66,1232,5
65,939,5

Maximum load is 65 user(s) over 5 second(s) (13.0 users/second) with a response time of 939 ms.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice how &amp;ldquo;maxload&amp;rdquo; used a binary search to automatically find the maximum load that the service could handle before the maximum response times went out of bounds. Neat.&lt;/p&gt;

&lt;p&gt;Also notice that &amp;ldquo;maxload&amp;rdquo; outputs a CSV of every sample taken. This CSV is useful to graph as a scatterplot to see graphically how the response time varies depending on the number of users. We generate these scatterplot graphs often enough that we&amp;rsquo;ll probably extend &amp;ldquo;maxload&amp;rdquo; in the future to just generate a scatterplot image automatically.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;bottleneck-isolation&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Bottleneck isolation&lt;/h3&gt;

&lt;p&gt;Once you&amp;rsquo;ve determined the maximum load that your service can support, you can ask yourself whether that load is good enough, based on the level of traffic that you forecast your site will receive in the near future.&lt;/p&gt;

&lt;p&gt;Should the maximum load not be good enough, you&amp;rsquo;ll want to isolate the &lt;strong&gt;bottleneck&lt;/strong&gt; in the system that is constraining the maximum load. Then you can focus on optimizing that bottleneck so that the maximum load increases to be good enough. Note that if you optimize a bottleneck in one area sufficiently, you may find that the bottleneck moves to a different location.&lt;/p&gt;

&lt;p&gt;For a web service, the most common bottlenecks in our experience are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU

&lt;ul&gt;
&lt;li&gt;Is the CPU usage 100% on some box?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Network

&lt;ul&gt;
&lt;li&gt;Are the number of synchronous database requests made by the application tier to the database tier very high (i.e. more than a dozen or so)?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Memory

&lt;ul&gt;
&lt;li&gt;Is there no available memory remaining on some box?&lt;/li&gt;
&lt;li&gt;Is there paging activity on some box?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IOPS

&lt;ul&gt;
&lt;li&gt;Are the IOPS the maximum for the storage type on some box?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Concurrency Configuration

&lt;ul&gt;
&lt;li&gt;Is the &lt;a href=&quot;https://docs.gunicorn.org/en/stable/settings.html#worker-processes&quot;&gt;maximum number of worker processes&lt;/a&gt; active? (Gunicorn)&lt;/li&gt;
&lt;li&gt;Is the &lt;a href=&quot;https://nginx.org/en/docs/ngx_core_module.html#worker_connections&quot;&gt;maximum number of connections per worker process&lt;/a&gt; being reached? (Nginx)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Disk Usage

&lt;ul&gt;
&lt;li&gt;Has the maximum quota on the /tmp filesystem been reached?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To isolate the bottleneck, use &amp;ldquo;perftest run&amp;rdquo; to start generating a load on the service equivalent to the maximum load  it can handle (as measured previously by &amp;ldquo;perftest maxload&amp;rdquo;) for a long time interval, say 10 minutes. While that load is being generated, use monitoring tools to look at the usage of CPU, Memory, IOPS, and other resources on each box in the system to look for saturation. When you find the saturated resource, that&amp;rsquo;s the bottleneck.&lt;/p&gt;

&lt;p&gt;Once you&amp;rsquo;ve located the bottleneck, there are usually a few options to optimize it away. To give you some ideas, here are some bottlenecks that the TechSmart website has hit in its performance testing (from least to most recently):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not enough frontend workers

&lt;ul&gt;
&lt;li&gt;Saturated resource: All frontend Gunicon workers busy 100% of the time, yet not 100% of the CPU utilized&lt;/li&gt;
&lt;li&gt;Fix: Reconfigure Gunicorn to increase the worker count to (2*N + 1), where N is the number of CPU cores.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Too many database requests

&lt;ul&gt;
&lt;li&gt;Saturated resource: Frontends busy waiting on the network for dozens of synchronous database queries to complete for a single page load&lt;/li&gt;
&lt;li&gt;Fixes:

&lt;ul&gt;
&lt;li&gt;Optimize frontend logic to reduce the number of database queries per page load to less than a dozen.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Use automated tests to &lt;a href=&quot;/articles/2021/02/09/database-clamps-deterministic-performance-tests-for-database-dependent-code/&quot;&gt;clamp the database query count&lt;/a&gt; so that it doesn&amp;rsquo;t increase.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Not enough frontend CPU

&lt;ul&gt;
&lt;li&gt;Saturated resource: 100% CPU on each box in the frontend cluster&lt;/li&gt;
&lt;li&gt;Fix: Increase frontend cluster size from 2 up to 5 boxes. At this point the bottleneck moves elsewhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Not enough database IOPS

&lt;ul&gt;
&lt;li&gt;Saturated resource: IOPS is maximum for the database storage type (i.e. Magnetic or SSD).&lt;/li&gt;
&lt;li&gt;Fixes:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2022/07/07/compressed-text-field-for-django-and-mysql-is-released/&quot;&gt;Shrink database contents with compression&lt;/a&gt; to reduce persisted data volume.&lt;/li&gt;
&lt;li&gt;Switch database storage type from Magnetic to SSD to increase the maximum IOPS.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Other potential fixes:

&lt;ul&gt;
&lt;li&gt;Increase RAM on database servers so that the database contents fit into memory, making IOPS irrelevent.&lt;/li&gt;
&lt;li&gt;Scale reads. Create read replicas of the database.&lt;/li&gt;
&lt;li&gt;Scale writes. Shard the database to multiple database masters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Not enough remaining concurrent requests quota

&lt;ul&gt;
&lt;li&gt;Saturated resource: Maximum number of concurrent requests to Nginx&lt;/li&gt;
&lt;li&gt;Fix: Increase configured maximum number of concurrent requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And here are some bottlenecks that our performance testing has identified we will hit under much higher loads than what we currently experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not enough database CPU

&lt;ul&gt;
&lt;li&gt;Saturated resource: 100% CPU on the single master database server&lt;/li&gt;
&lt;li&gt;Potential fixes:

&lt;ul&gt;
&lt;li&gt;Cache more aggressively, so that requests are diverted from the database tier to the cache tier.&lt;/li&gt;
&lt;li&gt;Scale reads. Create read replicas of the database.&lt;/li&gt;
&lt;li&gt;Scale writes. Shard the database to multiple database masters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;overload-behavior&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Overload behavior&lt;/h3&gt;

&lt;p&gt;It is useful to determine what happens when your service is subjected to greater than its maximum load. In particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it &lt;strong&gt;reject&lt;/strong&gt; requests loudly?&lt;/li&gt;
&lt;li&gt;Does it &lt;strong&gt;drop&lt;/strong&gt; requests silently?&lt;/li&gt;
&lt;li&gt;Does it &lt;strong&gt;queue&lt;/strong&gt; requests? Up to a particular soft or hard limit?&lt;/li&gt;
&lt;li&gt;Does it &lt;strong&gt;crash&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;If it crashes, does it automatically &lt;strong&gt;restart&lt;/strong&gt;?&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;You should decide what desired behavior you want your system to exhibit when receiving a temporary over-maximum load (i.e. a &lt;strong&gt;spike&lt;/strong&gt;) or a sustained over-maximum load (i.e. a &lt;strong&gt;flood&lt;/strong&gt;). Then verify whether the actual behavior matches the desired behavior.&lt;/p&gt;

&lt;p&gt;If your service is generally written with &lt;em&gt;infinitely-flexible buffers&lt;/em&gt;, it&amp;rsquo;s likely that receiving sustained over-maximum load will causes requests to queue up until memory is exhausted, and the out-of-memory condition will cause the service to crash.&lt;/p&gt;

&lt;p&gt;On the other hand if your service is generally written with &lt;em&gt;fixed-size buffers&lt;/em&gt;, it&amp;rsquo;s likely that receiving any over-maximum load will cause requests to be rejected or dropped.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;end&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;End&lt;/h2&gt;

&lt;p&gt;Hopefully this article has provided some insight into concepts around performance testing and given you some ideas about how to implement or improve tooling to perform performance testing.&lt;/p&gt;

&lt;p&gt;If you have any improvements or other comments on the contents of this article &lt;a href=&quot;/contact&quot;&gt;I&amp;rsquo;d love to hear from you&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2022-02-06:

&lt;ul&gt;
&lt;li&gt;Mention more types of &lt;a href=&quot;#bottleneck-isolation&quot;&gt;bottlenecks&lt;/a&gt; I&amp;rsquo;ve
encountered at TechSmart since 2018.&lt;/li&gt;
&lt;li&gt;Bold common patterns of &lt;a href=&quot;#overload-behavior&quot;&gt;overload behavior&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add table of contents for easier navigation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;For the purposes of this article I define performance testing to include &lt;strong&gt;load testing&lt;/strong&gt; and &lt;strong&gt;stress testing&lt;/strong&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Many other performance testing tools focus not on the &lt;strong&gt;maximum&lt;/strong&gt; response time but rather on other measures such as the &lt;strong&gt;99th percentile&lt;/strong&gt; response time or the &lt;strong&gt;mean&lt;/strong&gt; response time, which are &lt;a href=&quot;https://www.youtube.com/watch?v=lJ8ydIuPFeU&quot;&gt;inappropriate to use&lt;/a&gt;.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;The most important request type for a particular simulation is determined by inspecting the source code for a simulation file and looking for a line like &lt;code&gt;val PROFILED_REQUEST_NAME = &quot;view_code&quot;&lt;/code&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;In Django, an easy way to eliminate a bunch of database queries is to make appropriate use of &lt;a href=&quot;https://docs.djangoproject.com/en/4.0/ref/models/querysets/#select-related&quot;&gt;&lt;code&gt;select_related()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.djangoproject.com/en/4.0/ref/models/querysets/#prefetch-related&quot;&gt;&lt;code&gt;prefetch_related()&lt;/code&gt;&lt;/a&gt; to pre-fetch a group of relationships all at once (with a constant number of queries) rather than one at a time (with a variable number of queries, depending on how many relationships there are).&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2018/04/07/unsound-type-systems-are-still-useful</id>
   <title>Unsound type systems are still useful</title>
   <published>2018-04-07T00:00:00+00:00</published>
   <updated>2018-04-07T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2018/04/07/unsound-type-systems-are-still-useful/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;The conventional wisdom in the academic community &lt;a href=&quot;https://frenchy64.github.io/2018/04/07/unsoundness-in-untyped-types.html&quot;&gt;appears to be&lt;/a&gt; that a type system is not useful if it cannot be proven to be &lt;em&gt;sound&lt;/em&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;However as a software practitioner I definitely find unsound type systems to still be quite useful. The principal benefits that I get out of a type system include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identification of many common types of errors&lt;/strong&gt;, in particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;misspelled names of functions and variables,&lt;/li&gt;
&lt;li&gt;missing import statements,&lt;/li&gt;
&lt;li&gt;null-pointer dereference errors,&lt;/li&gt;
&lt;li&gt;type mismatch errors, and&lt;/li&gt;
&lt;li&gt;&lt;p&gt;inexhaustive case handling of type codes and algebraic data types.&lt;p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API documentation that is machine-checked&lt;/strong&gt; for consistency and correctness that cannot silently get outdated.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Common unsound type systems such as &lt;a href=&quot;https://www.infoworld.com/article/3066749/application-development/mypy-improves-static-type-checking-for-big-python-apps.html&quot;&gt;mypy&lt;/a&gt; and &lt;a href=&quot;http://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; typically provide all of these benefits.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;sound&lt;/em&gt; type system can additionally provide a few additional benefits that I don&amp;rsquo;t miss much in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;i&gt;All&lt;/i&gt; runtime types will be consistent with the static types assigned by the type system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This property permits the &lt;strong&gt;elimination of most or all runtime type checks&lt;/strong&gt;, which can improve the constant-factor performance of programs by a factor of 100 - 1,000x. I don&amp;rsquo;t miss this type of performance reduction because the programs I write - typically web applications - are usually I/O-bound rather than CPU-bound. Therefore I care far more about the &lt;em&gt;algorithmic&lt;/em&gt; performance of programs I write rather than the &lt;em&gt;constant-factor&lt;/em&gt; performance.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It is safe to fully &amp;ldquo;lean on the type system&amp;rdquo;&lt;/strong&gt; to locate and fix consistency errors when performing common refactorings such as renames, moves, and function signature changes.&lt;/p&gt;

&lt;p&gt;In absence of a sound type system it becomes necessary to lean on &lt;em&gt;tests&lt;/em&gt; instead of the type system to locate and fix consistency errors.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In short, I get a lot of mileage out of unsound type systems, so I would encourage those who research and implement type systems to still consider type systems that are unsound as worthy of study, such as the Gradual Typing family of type systems.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Soundness means that a type system never misjudges the runtime type of a value. In practice this means that (1) the type system defines a static type for &lt;em&gt;all&lt;/em&gt; variables and expressions and (2) type casts that override the type system are &lt;em&gt;not&lt;/em&gt; permitted.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;p&gt;I use the term &lt;b&gt;algorithmic performance&lt;/b&gt; to refer to the Big-Oh average case and worst case CPU performance of a particular program. I use the term &lt;b&gt;constant-factor performance&lt;/b&gt; to refer to differences in program CPU performance due to differences in constant factors only.&lt;/p&gt;&lt;p&gt;For example in comparing an implementation of merge sort on integers written in a statically-typed language such as C to an implementation written in a dynamically-typed language such as Python, they will be equivalently fast in terms of Big-Oh notation (so they have the same algorithmic performance) but the C version will be faster in terms of constant-factor performance due to having no runtime type checks.&lt;/p&gt;&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2018/01/20/how-to-implement-a-large-software-feature</id>
   <title>How to implement a large software feature</title>
   <published>2018-01-20T00:00:00+00:00</published>
   <updated>2018-01-20T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2018/01/20/how-to-implement-a-large-software-feature/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I just started implementing my first big new software feature since the start of the New Year. I thought I&amp;rsquo;d outline my process since I don&amp;rsquo;t think I&amp;rsquo;ve written it down before.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s begin: A feature request comes in. In my case:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Dynamic Calendar for Teachers:&lt;/strong&gt; Extend our existing Plan page, which shows a calendar of daily activities, such that classroom teachers (our customers) can move activities around on the calendar without engaging our support team over live chat.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I&amp;rsquo;m working in a large existing codebase and this feature needs to be integrated with existing code. This is a common situation.&lt;/p&gt;

&lt;h3&gt;1. Review the current behavior&lt;/h3&gt;

&lt;p&gt;We already have a &lt;strong&gt;Dynamic Calendar for Staff&lt;/strong&gt; feature implemented that our support staff can use to rearrange calendars. It just hasn&amp;rsquo;t been released directly to teachers because there a few rough edges that need to be polished off first.&lt;/p&gt;

&lt;p&gt;Therefore this new feature is primarily a UI change, publicizing existing functionality, along with some backend adjustments to the functionality to make it bulletproof.&lt;/p&gt;

&lt;p&gt;I annotate a screenshot of the current Dynamic Calendar dropdown that staff can use to manipulate days on the calendar:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2018/how-to-implement-a-large-software-feature/before.png&quot;&gt;
    &lt;img alt=&quot;High-fidelity UX mockup: Weekly calendar with open dropdown menu, that is divided into 3 sections.&quot; src=&quot;/assets/2018/how-to-implement-a-large-software-feature/before.png&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;2. Design the new behavior. Write out the delta between the old and new behaviors.&lt;/h3&gt;

&lt;p&gt;I mock up proposed new UI. In this case I just use a text file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;--------------------
Add empty day / Add teaching day...
Remove empty day
-------------------- ▲ teacher sees
Go to admin page ❏
Add empty day (without relayout)
Remove empty day (without relayout)
Relayout
-------------------- ▲ staff sees
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In other cases I actually create a visual mockup using a diagram on paper or a graphics program.&lt;/p&gt;

&lt;p&gt;I also write up a summary of behavioral changes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;* Remove teacher actions (because deprecated):
    - Set as non-teaching day
* Add teacher actions:
    - Add teaching day...
        - Needs to prompt for start/end times.
            &amp;gt; Suggest specific options based on existing schedule.
            &amp;gt; Allow full customization as well.
* Publicize and change actions:
    - Add empty day
        - May now perform a relayout. Is slow. Can fail.
        - Adds day at the current day rather than after it.
    - Remove empty day
        - May now perform a relayout. Is slow. Can fail.
        - Continues to require day to be empty of skipped objects too.
          Teacher can now see skipped objects and move them elsewhere
          before removing an otherwise empty day.
* Remove staff actions (because deprecated):
    - Domino step
    - Domino cascade
* Add staff actions:
    - Add empty day (without relayout)
    - Remove empty day (without relayout)
    - Relayout
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These behavior changes also imply the addition of some new popups, which I also mock up in another text file.&lt;/p&gt;

&lt;p&gt;With the new behavior now clearly written out, it&amp;rsquo;s time to review it with a member of the User Experience team. They approve the proposed design with some changes.&lt;/p&gt;

&lt;p&gt;I also review the new behavior with the member of the Engineering team most familar with the affected subsystems. In this example that person is myself, so there is no further action.&lt;/p&gt;

&lt;h3&gt;3. Write out engineering tasks that perform the deltas&lt;/h3&gt;

&lt;p&gt;For this example, here’s a simplified version of the tasks I write out:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[ ] Rip out all DC actions that involve a domino or other magic. #EasyWin
[ ] Merge &quot;can manage&quot; and &quot;can admin&quot; permissions to just &quot;can admin&quot;.
=== Familiar with DC logic. Prior system complexity minimized. [1]
[ ] Add &quot;Relayout&quot; action that redirects to the existing &quot;Recreate class calendar suffix&quot; page
[ ] Retitle:
    - Add empty day -&amp;gt; Add empty day (without relayout)
    - Remove empty day -&amp;gt; Remove empty day (without relayout)
[ ] Alter &quot;Add empty day&quot; to add *at* the specified day rather than *after*
=== Staff-facing actions are ready for release [1]
[ ] Add &quot;newdc&quot; feature flag
[ ] Implement new DCD action: Add empty day, behind &quot;newdc&quot; flag
    - ... (details elided)
[ ] Implement new DCD action: Remove empty day, behind &quot;newdc&quot; flag
    - ... (details elided)
=== Teacher-facing actions are ready for release. [3]
[ ] Announce the DC feature to teachers
    - ... (details elided)
[ ] Remove &quot;newdc&quot; feature flag
=== Released. [1]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I may review the engineering tasks with another member of the Engineering team if I uncover any additional details that merit review. In this example I do not.&lt;/p&gt;

&lt;p&gt;I update the estimated time for the feature on the Project Management calendar. If the new time estimate has significantly increased then I contact Project Management to see whether any external deadlines are impacted and to negotiate if they are.&lt;/p&gt;

&lt;h3&gt;4. Perform the engineering tasks&lt;/h3&gt;

&lt;p&gt;This is the easy part: Develop, test, code review, merge, repeat.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2017/04/09/the-trouble-with-global-variables</id>
   <title>The Trouble with Global Variables</title>
   <published>2017-04-09T00:00:00+00:00</published>
   <updated>2017-04-09T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2017/04/09/the-trouble-with-global-variables/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;You&amp;rsquo;ve probably heard that global variables are bad. Today I want to explain &lt;em&gt;why&lt;/em&gt; they are problematic, with examples, and give some design alternatives where you might be tempted to use a global variable.&lt;/p&gt;

&lt;h2&gt;What is a global?&lt;/h2&gt;

&lt;p&gt;A global is a variable from the environment that a function can directly read or write without going through a function parameter.&lt;/p&gt;

&lt;p&gt;For example, here is a &lt;code&gt;warn&lt;/code&gt; function that adds a warning message to a global warnings list.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;warnings = []

def warn(message):
    warnings.append(message)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;When is it tempting to use a global?&lt;/h2&gt;

&lt;p&gt;Globals are tempting to use when there are a large number of related functions that need to read or write a common piece of information.&lt;/p&gt;

&lt;p&gt;For example consider a parser that has a root &lt;code&gt;parse_calendar_file&lt;/code&gt; function that calls a tree of subordinate functions to parse data from a YAML document into domain objects. Any of these subordinate functions may emit warnings.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/the-trouble-with-global-variables/parse_calendar_file.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2&gt;Why are globals problematic?&lt;/h2&gt;

&lt;p&gt;Globals create hidden dependencies that are difficult to discover and easy to propagate.&lt;/p&gt;

&lt;h3&gt;Globals are hidden&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;Globals act as a kind of &lt;em&gt;hidden&lt;/em&gt; parameter or return value of any function that uses them, which callers may be unaware of. Such global-dependent functions are fragile and easy to misuse.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;A function that reads a global expects it to be in a particular state before the function is called. If it is not in the correct state, the function will misbehave. And yet you don&amp;rsquo;t see the global mentioned in the function&amp;rsquo;s parameter list.&lt;/p&gt;

&lt;p&gt;A function that writes a global relies on the global to return information to the caller or an ancestor of the caller. And yet you don&amp;rsquo;t see the global mentioned in the function&amp;rsquo;s return value.&lt;/p&gt;

&lt;p&gt;In fact to see whether a function depends on a global you &lt;em&gt;must&lt;/em&gt; crack it open and examine its implementation. This breaks encapsulation, requiring you to inspect the function&amp;rsquo;s private implementation and not just its public interface to discern how to use it properly. Thus functions that manipulate globals are easy to misuse.&lt;/p&gt;

&lt;h3&gt;Globals are viral&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;Globals silently infect both direct &lt;em&gt;and&lt;/em&gt; indirect callers such that they have a dependency on the global, which new callers may be unaware of. Globals create spooky action at a distance.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In the parsing example above consider what would happen if you were to invoke a subordinate parsing function like &lt;code&gt;parse_bell_schedule&lt;/code&gt; directly, without going through the root function that initializes the &lt;code&gt;warnings&lt;/code&gt; global. Since the call tree of the subordinate function eventually reaches &lt;code&gt;warn&lt;/code&gt;, which expects &lt;code&gt;warnings&lt;/code&gt; to be initialized, calling the subordinate function directly will crash!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/the-trouble-with-global-variables/write_crashes.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It is not possible to read only the implementation of the subordinate function &lt;code&gt;parse_bell_schedule&lt;/code&gt; to discern that it depends on the &lt;code&gt;warnings&lt;/code&gt; global: you have to read the implementation of &lt;em&gt;every&lt;/em&gt; function that it calls, directly or indirectly, to see whether it uses the global! This is a massive encapsulation violation of the entire call tree that leads to the global! Every function in the call tree becomes easy to misuse.&lt;/p&gt;

&lt;h3&gt;Globals are thread-hostile&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;Functions that depend on mutable globals directly or indirectly cannot be used safely in a multi-threaded program. Attempting to do so will create race conditions, garbage output, and crashes.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Consider what would happen if you had two threads that independently and simultaneously called the root function &lt;code&gt;parse_calendar_file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Say thread A gets halfway through parsing when B just starts parsing. Thread B will clobber thread A&amp;rsquo;s version of the &lt;code&gt;warnings&lt;/code&gt; global when it starts parsing. As thread A and B continue parsing, warnings from &lt;em&gt;both&lt;/em&gt; threads will be mixed together into a nonsensical mishmash. After the first-finishing thread  destroys the global, the other thread may crash when it tries to doubly destroy the global. Either way both threads will either return bogus warnings or crash outright.&lt;/p&gt;

&lt;p&gt;To make multi-threaded usage of &lt;code&gt;warnings&lt;/code&gt; safe, it is necessary for there to be a separate version of &lt;code&gt;warnings&lt;/code&gt; owned by each call tree or thread. Globals by definition are global in scope and are not themselves divisible into separate versions per call tree or thread.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;What can I use instead of a global?&lt;/h2&gt;

&lt;p&gt;Considering that the big issue with globals is that they are &lt;em&gt;invisible&lt;/em&gt; and, well, &lt;em&gt;globally&lt;/em&gt; scoped, let&amp;rsquo;s consider alternatives that are actually &lt;em&gt;visible&lt;/em&gt; and &lt;em&gt;more-tightly&lt;/em&gt; scoped.&lt;/p&gt;

&lt;h3&gt;Explicit Parameters&lt;/h3&gt;

&lt;p&gt;One way to eliminate a global variable is to just pass its value around as an explicit parameter.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This approach provides no encapsulation around the shared variable and doesn&amp;rsquo;t allow you to easily add additional shared variables to the same function group. This approach is thus suited to when you explicitly don&amp;rsquo;t want encapsulation, don&amp;rsquo;t anticipate adding new shared variables, and don&amp;rsquo;t want to change the variable itself, such as when you&amp;rsquo;re passing a Whole Object around.&lt;/p&gt;

&lt;p&gt;For our parsing example, we&amp;rsquo;ll create a &lt;code&gt;warnings&lt;/code&gt; parameter on all parsing functions:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/the-trouble-with-global-variables/explicit_parameters.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our parsing example really wants some encapsulation around the shared &lt;code&gt;warnings&lt;/code&gt; variable and is likely to want more shared variables later (like &lt;code&gt;errors&lt;/code&gt;) so the explicit parameter approach is not appropriate here.&lt;/p&gt;

&lt;h3&gt;Context Objects&lt;/h3&gt;

&lt;p&gt;A Context Object bundles together a bunch of variables that are shared among a set of related functions as fields. The related functions then take the Context Object as an explicit parameter.&lt;/p&gt;

&lt;p&gt;For our parsing example, we&amp;rsquo;ll create a &lt;code&gt;WarningsContext&lt;/code&gt; class which is then passed around among all parsing functions:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/the-trouble-with-global-variables/context_object.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It now becomes explicit as to which functions depend on the ability to issue warnings, at the cost of adding noise to the function signatures.&lt;/p&gt;

&lt;p&gt;In our parsing example if a new caller was introduced that wanted to call the subordinate &lt;code&gt;parse_bell_schedule&lt;/code&gt; function directly it would now be obvious that the caller would need to create and initialize a &lt;code&gt;WarningsContext&lt;/code&gt; object first and pass it to the subordinate function. No more crashes. Nice.&lt;/p&gt;

&lt;p&gt;Also notice that &lt;code&gt;WarningsContext&lt;/code&gt; is sufficiently encapsulated to be usable by not just the calendar file parser code but also &lt;em&gt;reusable&lt;/em&gt; by other code that wishes to generate warnings. Cool.&lt;/p&gt;

&lt;p&gt;If there is a desire to add another variable that the parsing functions all depend on (like &lt;code&gt;errors&lt;/code&gt;), it is easy to add it to the &lt;code&gt;WarningsContext&lt;/code&gt; class which is already being passed around everywhere, and then rename the class to something more specific like &lt;code&gt;ParsingContext&lt;/code&gt; or &lt;code&gt;CalendarFileParsingContext&lt;/code&gt;. However if you are using a very specific context name you probably want a Method Object instead&amp;hellip;&lt;/p&gt;

&lt;h3&gt;Method Objects&lt;/h3&gt;

&lt;p&gt;A Method Object is like a Context Object but is even more cohesive: it bundles together not only the shared variables but the functions themselves into a single class. This new class is instantiated internally by the root function and lives only for the duration of the original function call.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;For our parsing example we&amp;rsquo;ll create a &lt;code&gt;CalendarFileParser&lt;/code&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/the-trouble-with-global-variables/method_object.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A Method Object is especially useful when there are &lt;em&gt;many&lt;/em&gt; variables that are used by the same set of cohesive functions and these variables are tightly bound to the functions themselves.&lt;/p&gt;

&lt;p&gt;If we wanted to add an &lt;code&gt;errors&lt;/code&gt; variable to the parsing functions here in addition to &lt;code&gt;warnings&lt;/code&gt;, we&amp;rsquo;d just declare it as another field on &lt;code&gt;CalendarFileParser&lt;/code&gt;. Easy.&lt;/p&gt;

&lt;h2&gt;Ende&lt;/h2&gt;

&lt;p&gt;Hopefully this discussion has been useful in explaining why global variables are to be avoided and what design techniques can be used instead.&lt;/p&gt;

&lt;p&gt;I anticipate the next few articles will continue on the theme of considerations and techniques when designing &lt;em&gt;large&lt;/em&gt; software systems. Stay tuned.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;You can get around the natural thread-hostility of a global variable by wrapping its value in a &lt;strong&gt;thread local&lt;/strong&gt;. A thread local is a little-known special kind of Cell object that stores an independent value depending on which thread it is accessed from. In Python see &lt;code&gt;threading.local&lt;/code&gt;. In Java see &lt;code&gt;java.lang.ThreadLocal&lt;/code&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;If you need to &lt;em&gt;modify&lt;/em&gt; the base of a shared variable when it is being passed around as an explicit parameter then you must &lt;em&gt;also&lt;/em&gt; pass back the altered variable through the return value. However this gets unwieldly very fast. In such cases you probably want to either wrap the shared variable in a Cell so that you don&amp;rsquo;t have to modify the variable itself or use a Context Object. If you truly must use explicit parameters and return values, such as in a functional language that disallows direct mutation of values, consider using the Monad pattern to reduce syntactic overhead.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;A Method Object gets its name from the fact that it exposes only a single public method and all of the other private methods and fields exist to serve that method.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2017/03/25/how-to-design-large-programs-with-abstraction-and-encapsulation</id>
   <title>How to Design Large Programs with Abstraction and Encapsulation</title>
   <published>2017-03-25T00:00:00+00:00</published>
   <updated>2017-03-25T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2017/03/25/how-to-design-large-programs-with-abstraction-and-encapsulation/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I spend a lot of time as a professional coder working on very large programs, attempting to grow them while also keeping them from collapsing under their own weight. This is hard.&lt;/p&gt;

&lt;h2&gt;Abstraction and Encapsulation&lt;/h2&gt;

&lt;h3&gt;The Challenge&lt;/h3&gt;

&lt;p&gt;A large program has a lot of behavior to specify. The complexity of the behavior specified by a program is roughly proportional to its size.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/abstraction-and-encapsulation/1-lines.svg&quot; alt=&quot;Lines&quot; /&gt;&lt;/p&gt;

&lt;p&gt;However a coder, being only human, can only hold a fixed amount of &lt;strong&gt;concepts&lt;/strong&gt; in their head at once.&lt;/p&gt;

&lt;h3&gt;Chunking&lt;/h3&gt;

&lt;p&gt;The number of concepts can be reduced by &lt;strong&gt;chunking&lt;/strong&gt; them into larger concepts that are less numerous. For example a bundle of &lt;em&gt;lines&lt;/em&gt; can be chunked into a single &lt;em&gt;function&lt;/em&gt; or a &lt;em&gt;method&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2017/abstraction-and-encapsulation/2-functions.svg&quot;&gt;
    &lt;img alt=&quot;Functions&quot; src=&quot;/assets/2017/abstraction-and-encapsulation/2-functions.svg&quot; style=&quot;max-width: 100%&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chunking allows you to reduce the total number of concepts that you need to keep in your head at once.&lt;/p&gt;

&lt;p&gt;There are many kind of chunks. The kinds I normally think about are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lines&lt;/li&gt;
&lt;li&gt;Paragraphs&lt;/li&gt;
&lt;li&gt;Functions, Methods&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Classes&lt;/li&gt;
&lt;li&gt;Modules&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Packages&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Assemblies, Libraries&lt;/li&gt;
&lt;li&gt;Binaries&lt;/li&gt;
&lt;li&gt;Services&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Abstractions&lt;/h3&gt;

&lt;p&gt;A larger unit that is created by bundling smaller units is called an &lt;strong&gt;abstraction&lt;/strong&gt;. An abstraction typically has:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a name&lt;/li&gt;
&lt;li&gt;a public surface area, and&lt;/li&gt;
&lt;li&gt;a private interior.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;For a &lt;em&gt;function&lt;/em&gt; unit, it has a function name, some number of &lt;em&gt;parameters&lt;/em&gt; and a &lt;em&gt;return value&lt;/em&gt; which serves as the public surface area, and a body of code lines which serve as the private interior.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/abstraction-and-encapsulation/3-func_anatomy.svg&quot; alt=&quot;Anatomy of a Function&quot; /&gt;&lt;/p&gt;

&lt;h3&gt;Encapsulation&lt;/h3&gt;

&lt;p&gt;An abstraction reduces global complexity by hiding (or &lt;strong&gt;encapsulating&lt;/strong&gt;) its large private interior, exposing only the smaller public surface area to the rest of the system. One only needs to understand the smaller public surface area when using the function and not the details of the private interior.&lt;/p&gt;

&lt;p&gt;A well-designed abstraction thus strives to &lt;strong&gt;minimize its public surface area&lt;/strong&gt; while maximizing its private interior.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; Such an abstraction takes up only small mental space relative to its interior complexity.&lt;/p&gt;

&lt;p&gt;As an example of minimizing public surface area, let&amp;rsquo;s consider the example of a larger kind of unit, a &lt;em&gt;class&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/abstraction-and-encapsulation/4-class_anatomy.svg&quot; alt=&quot;Anatomy of a Class&quot; /&gt;&lt;/p&gt;

&lt;p&gt;By extension of the principle above, &lt;strong&gt;everything should be private by default&lt;/strong&gt;; only those methods that need to be public (because they are used externally) should be made public.&lt;/p&gt;

&lt;p&gt;If a method on a class is declared public when it is only used internally, you can perform a &lt;strong&gt;Refactor Privatize&lt;/strong&gt; to make it private.&lt;/p&gt;

&lt;p&gt;The same principle applies yet again to &lt;em&gt;modules&lt;/em&gt;, a larger kind of unit:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2017/abstraction-and-encapsulation/5-module_anatomy.svg&quot; alt=&quot;Anatomy of a Module&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Again, everything should be private by default.&lt;/p&gt;

&lt;h3&gt;Combining Encapsulated Abstractions&lt;/h3&gt;

&lt;p&gt;Encapsulated abstractions really shine in reducing program complexity when you combine them together.&lt;/p&gt;

&lt;p&gt;Without abstractions everything can depend on everything else which creates a potential combinatorial explosion of complexity. By contrast &lt;em&gt;with&lt;/em&gt; abstractions, the local complexity is bounded much more tightly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2017/abstraction-and-encapsulation/complexity_comparison.png&quot;&gt;
    &lt;img alt=&quot;Complexity with and without abstractions&quot; src=&quot;/assets/2017/abstraction-and-encapsulation/complexity_comparison.png&quot; style=&quot;max-width: 100%&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Within an abstraction the maximum local complexity is proportional to the size of that particular abstraction&amp;rsquo;s private interior plus the size of the public surface areas of all other abstractions.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Names Matter&lt;/h2&gt;

&lt;p&gt;It is worth noting that &lt;strong&gt;a name by itself serves as an kind of abstraction&lt;/strong&gt;. A good function name can tell you what the function does without you needing to crack it open and read its implementation. A good class name tells you what it represents, what it is responsible for, what it is, and what it is not.&lt;/p&gt;

&lt;p&gt;If you have to look behind a name to figure out what something does, the name needs to be improved via a &lt;strong&gt;Refactor Rename&lt;/strong&gt;. Refactor Rename is probably the most common refactoring I apply out of all the kinds of refactorings I use.&lt;/p&gt;

&lt;p&gt;For simple names, &lt;strong&gt;coding conventions&lt;/strong&gt; related to names often can tell you a lot. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Methods:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setFoo&lt;/code&gt; - Sets the &amp;ldquo;foo&amp;rdquo; property on a class. Take a single value as a parameter and returns nothing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getFoo&lt;/code&gt; - Gets the &amp;ldquo;foo&amp;rdquo; property on a class. Takes no parameters and returns the value.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initFoo&lt;/code&gt;, &lt;code&gt;setupFoo&lt;/code&gt; - Designed to be called once.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;updateFoo&lt;/code&gt; - Designed to be called multiple times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Variables

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;curFoo&lt;/code&gt; - The current element when iterating over a collection of foos.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt; - An uninteresting loop counter.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;e&lt;/code&gt;, &lt;code&gt;f&lt;/code&gt; - An uninteresting exception or event.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minFoo&lt;/code&gt;, &lt;code&gt;maxFoo&lt;/code&gt; - A minimum or maximum permissive value for foo, inclusive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limFoo&lt;/code&gt; - A maximum permissive value for foo, exclusive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fooIndex&lt;/code&gt; - A 0-based position of something.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fooOrdinal&lt;/code&gt; - A 1-based position of something.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOUD_CASE&lt;/code&gt; - A constant.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;&lt;em&gt;To Be Continued&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve got many other techniques for designing large programs. In future articles I hope to share some of these with you.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;I&amp;rsquo;m intentionally oversimplifying: Program complexity actually tends to grow with the &lt;em&gt;square&lt;/em&gt; of its size rather than linearly because all pieces of the program can depend on the other pieces and these dependencies contribute to the program complexity.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;A method is kind of function that is attached to a class.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;A module contains functions, classes, and variables, among other things.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;A package is a module that contains submodules.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201/&quot;&gt;A Philosophy of Software Design&lt;/a&gt; makes the same recommendation under the guidance &amp;ldquo;Modules should be deep&amp;rdquo;, where a &amp;ldquo;deep module&amp;rdquo; is an abstraction whose public surface area is small compared to the volume of its private interior.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2016/05/21/glue-in-functional-programming-languages</id>
   <title>Glue in Functional Programming Languages</title>
   <published>2016-05-21T00:00:00+00:00</published>
   <updated>2016-05-21T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2016/05/21/glue-in-functional-programming-languages/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.cse.chalmers.se/~rjmh/Papers/whyfp.html&quot;&gt;Why Functional Programming Matters&lt;/a&gt; is a famous paper on the merits of functional programming&amp;nbsp;(FP). It argues that FP has two big special tools for &lt;em&gt;glueing&lt;/em&gt; programs together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Higher-order functions can be easily composed&lt;/strong&gt; with other functions to create powerful composite functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy evaluation&lt;/strong&gt; allows efficient processing of streams and large data structures.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;Higher-Order Functions, meet List Comprehensions&lt;/h3&gt;

&lt;p&gt;I would like to note that Python — a modern imperative language that also supports functional and object-oriented paradigms — has not only higher order functions but something even better: &lt;strong&gt;list&amp;nbsp;comprehensions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;List comprehensions allow very succinct composition of user functions with the most important higher-order functions: &lt;code&gt;map&lt;/code&gt;, and &lt;code&gt;filter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Compare the following paired examples, showing a list comprehension first, followed by a composition of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[n * 2 for n in nums]&lt;/code&gt;&lt;br/&gt;
&lt;code&gt;nums.map(lambda n: n * 2)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[n for n in nums if n % 2 == 0]&lt;/code&gt;&lt;br/&gt;
&lt;code&gt;nums.filter(lambda n: n % 2 == 0)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[item.name for item in items if item is not None]&lt;/code&gt;&lt;br/&gt;
&lt;code&gt;items.filter(lambda item: item is not None).map(lambda item: item.name)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I would argue that in all of these cases the list comprehension is both (1) easier to understand and (2)&amp;nbsp;more succinct.&lt;/p&gt;

&lt;h3&gt;Lazy Evaluation, meet Generators and Coroutines&lt;/h3&gt;

&lt;p&gt;Lazy evaluation can certainly be very expressive for processing large data structures, compared with greedy evaluation. However I would like to note the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lazy evaluation &lt;strong&gt;significantly complicates using a traditional step-by-step debugger tool to step through a program&lt;/strong&gt;:&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; the current instruction pointer constantly warps up and down the call stack, which can be very confusing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lazy evaluation &lt;strong&gt;interacts poorly with error handling, I/O, and other side effects&lt;/strong&gt;.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This limits lazy evaluation&amp;rsquo;s advantages in processing large data structures to only those structures which are &lt;em&gt;in-memory&lt;/em&gt; or &lt;em&gt;procedurally generated&lt;/em&gt; rather than the (IMHO more-common) structures that reside &lt;em&gt;on disk&lt;/em&gt; or must be fetched &lt;em&gt;over the network&lt;/em&gt; - which must be read with I/O and may be malformed, thus requiring error handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pervasive use of lazy evaluation introduces unnecessary context switching overhead that &lt;strong&gt;degrades the constant-factor performance of algorithms&lt;/strong&gt; for which greedy evaluation would be acceptable. This makes pervasive lazy evaluation unsuitable for certain domains, such as systems domains.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Instead of &lt;em&gt;pervasive&lt;/em&gt; lazy evaluation, I find it sufficient to have lazy evaluation &lt;em&gt;on demand&lt;/em&gt; in the form of Python&amp;rsquo;s &lt;strong&gt;generators&lt;/strong&gt;, &lt;strong&gt;generator comprehensions&lt;/strong&gt;, and &lt;strong&gt;coroutines&lt;/strong&gt; when needed.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Presumably this is why Haskell does not ship with a traditional debugger. (Or at least I am not able to locate documentation for one.)&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Presumably this is one reason why Haskell does not allow unconstrained side effects, although there are many other reasons for having such constraints.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2016/05/17/abandonment-vs-unchecked-exceptions-for-error-handling</id>
   <title>Abandonment vs. Unchecked Exceptions for Error Handling</title>
   <published>2016-05-17T00:00:00+00:00</published>
   <updated>2016-05-17T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2016/05/17/abandonment-vs-unchecked-exceptions-for-error-handling/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Read a very interesting article about &lt;a href=&quot;http://joeduffyblog.com/2016/02/07/the-error-model/&quot;&gt;error handling in Midori&lt;/a&gt; recently, and it got me thinking about errors again. I&amp;rsquo;ve thought about errors a lot in the past, as you can see in my old &lt;a href=&quot;/articles/2013/07/13/error-handling/&quot;&gt;Error Handling&lt;/a&gt; article from 2013.&lt;/p&gt;

&lt;p&gt;Midori mentions a few mechanisms for handling errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;error codes&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;unchecked exceptions&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;checked exceptions&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;abandonment&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Midori has chosen to run with&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;abandonment&lt;/em&gt; for bugs, and&lt;/li&gt;
&lt;li&gt;&lt;em&gt;checked exceptions&lt;/em&gt; for most regular errors,&lt;/li&gt;
&lt;li&gt;&lt;em&gt;error codes&lt;/em&gt; for other regular errors.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;These seem to be reasonable choices given the special constraints of a language intended for systems, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;correctness&lt;/strong&gt; is more important than convenience,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;constant-factor performance&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; is important,&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;However I work mostly in application domains rather than system domains, so I wouldn&amp;rsquo;t make these same choices. In particular &lt;em&gt;abandonment&lt;/em&gt; really gets under my skin.&lt;/p&gt;

&lt;h3&gt;Abandonment&lt;/h3&gt;

&lt;p&gt;Abandonment in Midori is used for bugs and serious errors where there is no expectation that the error condition can be handled sensibly. Abandonment tears down the entire process.&lt;/p&gt;

&lt;p&gt;I have a few problems with this approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abandonment assumes that the &lt;em&gt;process&lt;/em&gt; is the primary isolation boundary.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a web server, for example, a single &lt;em&gt;request&lt;/em&gt; being handled would be a more appropriate boundary. It would be better to abort only the current request rather than bring down the entire web server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abandonment provides no opportunity for its error condition to be handled in an alternative fashion.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, code that intentionally allocates large blocks of memory on a regular basis may in fact be prepared to handle out of memory conditions, which would normally trigger abandonment.&lt;/p&gt;

&lt;p&gt;Granted, you can often support this scenario by bifurcating the API, providing one allocate-memory function that returns an explicit error code on failure and a different allocate-memory function that abandons on failure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;But there is one big advantage to using abandonment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better constant-factor performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using abandonment in place of unchecked exceptions means that there is no need to pepper functions everywhere with the low-level code needed to propagate unchecked exceptions. Such code globally degrades constant-factor performance of all functions in the language.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Unchecked Exceptions&lt;/h3&gt;

&lt;p&gt;In most modern programming languages intended for applications (as opposed to systems), &lt;em&gt;unchecked exceptions&lt;/em&gt; are used for reporting bugs. They have the following advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unchecked exceptions fail fast, terminating the process by default.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is no different than abandonment so far, however&amp;hellip;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unchecked exceptions &lt;em&gt;can&lt;/em&gt; be caught by a higher level error handler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This additional flexibily is useful for web servers, parsers, and other applications that expect to encounter errors but don&amp;rsquo;t want to crash entirely in the presence of errors.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;But:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unchecked exceptions degrade constant-factor performance.&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However this typically doesn&amp;rsquo;t matter in application domains. Only &lt;em&gt;algorithmic performance&lt;/em&gt; matters.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;I think abandonment is a reasonable approach for systems languages but I still prefer unchecked exceptions myself for application languages. I prefer the additional flexibility you get with unchecked exceptions and don&amp;rsquo;t mind the performance difference.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/07/13/error-handling/&quot;&gt;Error Handling&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Discusses considerations and specific implementation techniques for writing code that is robust in the presence of errors.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/11/22/error-handling-styles/&quot;&gt;Error handling styles in programming&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Summarizes the most prominent strategies for handling runtime errors.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;As used in this article, &lt;strong&gt;constant-factor performance&lt;/strong&gt; refers to being sensitive to high constant factors in program time costs. This is in contrast to &lt;strong&gt;algorithmic performance&lt;/strong&gt; which cares primarily about avoiding, for example, an O(n&lt;sup&gt;2&lt;/sup&gt;) algorithm where an O(n) algorithm would suffice.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2016/04/22/notes-on-the-clean-coder</id>
   <title>Notes on &amp;ldquo;The Clean Coder&amp;rdquo;</title>
   <published>2016-04-22T00:00:00+00:00</published>
   <updated>2016-04-22T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2016/04/22/notes-on-the-clean-coder/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I recently picked up a copy of &lt;a href=&quot;http://www.amazon.com/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073/ref=as_li_ss_tl?ie=UTF8&amp;amp;keywords=the%20clean%20coder&amp;amp;qid=1461339725&amp;amp;ref_=sr_1_1&amp;amp;sr=8-1&amp;amp;linkCode=ll1&amp;amp;tag=dafo07-20&amp;amp;linkId=11da6a52e5ac10bdef1499cb5b5fab88&quot;&gt;The Clean Coder&lt;/a&gt;: An excellent book about the non-technical aspects of being a senior software engineer.&lt;/p&gt;

&lt;p&gt;Below are my notes taken while reading the book.&lt;/p&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;xvi.&lt;/div&gt;


&lt;p&gt;Management sometimes doesn&amp;rsquo;t view software engineers as professionals in the same way, for example, they treat lawyers as professionals.&lt;/p&gt;

&lt;p&gt;In this situation management is likely to babysit the engineers, micromanage them, and be more prone to asking them to sacrifice their personal lives for the current project.&lt;/p&gt;

&lt;p&gt;As an engineer this situation is undesirable. This book intends to show you how to present yourself and interact as a &lt;em&gt;professional&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;xxii.&lt;/div&gt;


&lt;p&gt;Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a software professional?&lt;/li&gt;
&lt;li&gt;How does a professional behave?&lt;/li&gt;
&lt;li&gt;How does a professional deal with conflict, tight schedules, and unreasonable managers?&lt;/li&gt;
&lt;li&gt;When, and how, should a professional say &amp;ldquo;no&amp;rdquo;?&lt;/li&gt;
&lt;li&gt;How does a professional deal with pressure?&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Values&lt;/h2&gt;

&lt;h3&gt;Responsible&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;10.&lt;/div&gt;


&lt;p&gt;&amp;ldquo;Upon reflection I realized that shipping without testing the routine had been irresponsible. The reason I neglected the test was so I could say I had shipped on time. It was about me saving face. I had not been concerned about the customer, nor about my employer. I had only been concerned about my own reputation.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;I should have taken responsibility early and told Tom that the tests weren&amp;rsquo;t complete and that I was not prepared to ship the software on time. That would have been hard, and Tom would have been upset. But no customers would have lost data, and no service managers would have called.&amp;rdquo;&lt;/p&gt;

&lt;h3&gt;Accountable&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;12.&lt;/div&gt;


&lt;p&gt;It is the lot of a professional to be accountable for errors even though errors are virtually certain. Practice apologizing.&lt;/p&gt;

&lt;p&gt;Apologies are necessary but insufficient. As you mature, your error rate should rapidly decrease toward the asymptote of zero.&lt;/p&gt;

&lt;h3&gt;Bugs that Escape&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;12.&lt;/div&gt;


&lt;p&gt;QA should find nothing.&lt;/p&gt;

&lt;p&gt;If a bug reaches QA, figure out why those bugs managed to escape your notice and do something to prevent it from happening again.&lt;/p&gt;

&lt;p&gt;Every time QA, or worse a &lt;em&gt;user&lt;/em&gt;, finds a problem, you should be surprised, chagrined, and determined to prevent it from happening again.&lt;/p&gt;

&lt;h3&gt;Strive for Quality&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;13.&lt;/div&gt;


&lt;p&gt;100% line coverage is a minimum bar of quality, in the opinion of Robert C. Martin.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;15.&lt;/div&gt;


&lt;p&gt;Merciless refactoring: Every time you look at a module you make small, lightweight changes to it to improve its structure.&lt;/p&gt;

&lt;h3&gt;Learning &amp;amp; Teaching&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;16.&lt;/div&gt;


&lt;p&gt;Train yourself outside of work. For your career.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buy books.&lt;/li&gt;
&lt;li&gt;Goto conferences.&lt;/li&gt;
&lt;li&gt;Spend time each week practicing.&lt;/li&gt;
&lt;li&gt;Know the history of computer science. Many gems are there.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;notcc-page-location&quot;&gt;20.&lt;/div&gt;


&lt;p&gt;Train your juniors! The best way to learn is to teach.&lt;/p&gt;

&lt;h3&gt;Know Your Business Domain&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;21.&lt;/div&gt;


&lt;p&gt;Know your business domain well enough to be able to recognize and challenge specification errors.&lt;/p&gt;

&lt;h2&gt;Estimates &amp;amp; Saying No&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;25.&lt;/div&gt;


&lt;p&gt;Stick to your guns RE schedule estimates. Professionals speak truth to power. Professionals have the courage to say no to their managers.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;26-28. 30.&lt;/div&gt;


&lt;p&gt;Negotiate!&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;30.&lt;/div&gt;


&lt;p&gt;Being a &lt;em&gt;team player&lt;/em&gt; means player your position as well as you possibly can, and helping out your teammates when they get into a jam.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;32-36.&lt;/div&gt;


&lt;p&gt;There is no &amp;ldquo;trying&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;If you are not holding back some energy in reserve, if you don&amp;rsquo;t have a new plan, if you aren&amp;rsquo;t going to change your behavior, and if you are reasonably confident in your original estimate, then promising to try is fundamentally dishonest. You are &lt;em&gt;lying&lt;/em&gt;. And you are probably doing it to save face and to avoid a confrontation.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;34.&lt;/div&gt;


&lt;p&gt;(Passive aggression is when you let someone else hang themselves through inaction on your part.)&lt;/p&gt;

&lt;h2&gt;How and When to Code&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;58.&lt;/div&gt;


&lt;p&gt;Confidence and error-sense is the key to mastery.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;59.&lt;/div&gt;


&lt;p&gt;Write code to reveal intent.&lt;/p&gt;

&lt;p&gt;Worrying? Tired? Don&amp;rsquo;t code!&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;62-64.&lt;/div&gt;


&lt;p&gt;The author avoids the flow zone. I find it useful for routine code, and less useful for novel code.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;63.&lt;/div&gt;


&lt;p&gt;Music can be a plus or minus when writing code. It only works well for me when I&amp;rsquo;m writing routine code (and not novel code).&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;63.&lt;/div&gt;


&lt;p&gt;Interruptions happen. Try not to be rude.&lt;/p&gt;

&lt;p&gt;Refinding your place after an interruption can be tricky. I personally find having an active card useful, as I can just review the card and the checklist on it that I was working through.&lt;/p&gt;

&lt;h2&gt;Automated Tests&lt;/h2&gt;

&lt;h3&gt;Acceptance Tests&lt;/h3&gt;

&lt;p&gt;Acceptance tests are a special kind of automated test that specifically test the &lt;em&gt;stakeholder-desired&lt;/em&gt; behaviors of a feature. Once the acceptance tests pass, the feature is &amp;ldquo;done&amp;rdquo; from the perspective of the stakeholders. This is extremely powerful.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;100.&lt;/div&gt;


&lt;p&gt;Acceptance tests should be written as a collaboration of the stakeholders and the programmers.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;109.&lt;/div&gt;


&lt;p&gt;Unit tests and acceptance tests (which are not the same thing) are documents first and tests second. Their primary purpose is to formally document the design, structure, and behavior of the system. The fact that they automatically verify the design, structure, and behavior that they specify is wildly useful, but the specification is the true purpose.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;110.&lt;/div&gt;


&lt;p&gt;Make sure that all your unit tests and acceptance tests are run several times per day in a &lt;em&gt;continuous integration&lt;/em&gt; system.&lt;/p&gt;

&lt;p&gt;It is very important to keep the CI tests running at all times. A broken build in the CI system should be viewed as an emergency, a &amp;ldquo;stop the presses&amp;rdquo; event.&lt;/p&gt;

&lt;h3&gt;Other kinds of automated tests&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;114.&lt;/div&gt;


&lt;p&gt;Automated tests can act to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Specify&lt;/em&gt; the desired behavior or properties of a component.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Characterize&lt;/em&gt; the current behavior of a component. Useful to detect unexpected changes. Unlike a specifying test, a characterizing test does not worry as much whether the behavior being tested is actually the intended behavior.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&quot;notcc-page-location&quot;&gt;116-117.&lt;/div&gt;


&lt;p&gt;Automated tests can be classified based on the size of the things they put under test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit tests - Test individual functions or classes.&lt;/li&gt;
&lt;li&gt;Component tests - Test individual components or features.&lt;/li&gt;
&lt;li&gt;Integration tests - Test how multiple components or features interact.&lt;/li&gt;
&lt;li&gt;System tests - Test the entire system. Throughput and performance tests are commonly of this variety.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Time Management&lt;/h2&gt;

&lt;h3&gt;Meetings&lt;/h3&gt;

&lt;p&gt;There are two truths about meetings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Meetings are necessary.&lt;/li&gt;
&lt;li&gt;Meetings are huge time wasters.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Be very careful about which meetings you attend and which you politely refuse.&lt;/p&gt;

&lt;p&gt;One of the most important duties of your manager is to keep you out of meetings.&lt;/p&gt;

&lt;p&gt;Have an agenda and a goal: If you are asked to go to a meeting, make sure you know what discussions are on the table, how much time is allotted for them, and what goal is to be achieved. If you can&amp;rsquo;t get a clear answer on these things, then politely decline to attend.&lt;/p&gt;

&lt;h3&gt;Focus: A scarce resource&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;127-128.&lt;/div&gt;


&lt;p&gt;Focus is a scarce resource, rather like manna.&lt;/p&gt;

&lt;p&gt;It is wise to manage one&amp;rsquo;s time to take advantage of when focus-manna is available. Focus-manna is a decaying resource so it often needs to be used when it is available.&lt;/p&gt;

&lt;p&gt;Sleep is paramount to recharge focus.&lt;/p&gt;

&lt;p&gt;Power naps also work well for me personally.&lt;/p&gt;

&lt;h3&gt;Blind alleys&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;131.&lt;/div&gt;


&lt;p&gt;The Rule of Holes: When you are in one, stop digging.&lt;/p&gt;

&lt;h3&gt;Messes&lt;/h3&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;132.&lt;/div&gt;


&lt;p&gt;Messes slow you down but don&amp;rsquo;t stop you. Messes are worse than blind alleys because you can always see the way forward, and it always looks shorter than the way back (but it isn&amp;rsquo;t).&lt;/p&gt;

&lt;h2&gt;Estimates&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;138.&lt;/div&gt;


&lt;p&gt;Businesses like to view estimates as commitments. Developers like to view estimates as guesses.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A commitment is something you must achieve.&lt;/li&gt;
&lt;li&gt;An estimate is a guess. No commitment is implied.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Commitment is about certainty. Other people are going to make plans based on your commitments.&lt;/p&gt;

&lt;p&gt;An estimate is not number, despite it often being presented as such. Rather, it is a &lt;em&gt;distribution&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;141.&lt;/div&gt;


&lt;p&gt;There is a system of estimation called &amp;ldquo;PERT&amp;rdquo; or &amp;ldquo;trivariate analysis&amp;rdquo;. You give an estimate as a combination of {Optimistic Estimate, Nominal Estimate, Pessimistic Estimate}, which creates a beta distribution. These distributions can be added together to determine the combined time distribution for performing a &lt;em&gt;series&lt;/em&gt; of tasks.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;141.&lt;/div&gt;


&lt;p&gt;Estimating tasks with a group of team-members is more accurate than estimating by oneself. There are many techniques for this. Probably the most famous is &amp;ldquo;planning poker&amp;rdquo;. There is also &amp;ldquo;affinity estimation&amp;rdquo; and &amp;ldquo;flying fingers&amp;rdquo;.&lt;/p&gt;

&lt;h2&gt;Pressure&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;153.&lt;/div&gt;


&lt;p&gt;You know what you believe by observing yourself in a crisis.&lt;/p&gt;

&lt;p&gt;If in a crisis you follow your disciplines, then you truly believe in those disciplines. On the other hand, if you change your behavior in a crisis, then you don&amp;rsquo;t truly believe in your normal behavior.&lt;/p&gt;

&lt;p&gt;Choose disciplines that you feel comfortable following in a crisis. Then follow them all the time.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;154.&lt;/div&gt;


&lt;p&gt;Avoid creating surprises. Nothing makes people more angry and less rational than surprises.&lt;/p&gt;

&lt;h2&gt;Teams&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;168.&lt;/div&gt;


&lt;p&gt;When assigning work to folks, there&amp;rsquo;s no such thing as half a person. You cannot sensibly tell a programmer to devote half their time to project A and half their time to project B.&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;169.&lt;/div&gt;


&lt;p&gt;For a 12-person team, here&amp;rsquo;s a suggested team composition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;7 devs&lt;/li&gt;
&lt;li&gt;2 testers &amp;ndash; Who write acceptance tests, focusing on correctness, failure, boundary cases.&lt;/li&gt;
&lt;li&gt;2 analysts &amp;ndash; Who write acceptance tests, focusing on business value and the happy path.&lt;/li&gt;
&lt;li&gt;1 project manager&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;notcc-page-location&quot;&gt;171.&lt;/div&gt;


&lt;p&gt;It&amp;rsquo;s reasonable to assign multiple projects to a single team. Particularly if the team has gelled.&lt;/p&gt;

&lt;p&gt;On the other hand assigning multiple projects to a single person is not a great idea.&lt;/p&gt;

&lt;h2&gt;Mentoring, Apprenticeship, and Craftsmanship&lt;/h2&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;182.&lt;/div&gt;


&lt;p&gt;Software apprenticeship: A very interesting idea. Consider the following levels of proficiency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Master&lt;/li&gt;
&lt;li&gt;Journeymen&lt;/li&gt;
&lt;li&gt;Apprentice / Intern&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;(See the descriptions in the book.)&lt;/p&gt;

&lt;div class=&quot;notcc-page-location&quot;&gt;184.&lt;/div&gt;


&lt;p&gt;A &lt;em&gt;craftsman&lt;/em&gt; is someone who works quickly, but without rushing, who provides reasonable estimates and meets commitments. A craftsman knows when to say no, but tries hard to say yes. A craftsman is a professional.&lt;/p&gt;

&lt;p&gt;School can teach the theory of computer programming. But school does not, and cannot teach the discipline, practice, and skill of being a craftsman.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2016/04/02/roles-on-software-teams</id>
   <title>Roles on Software Teams</title>
   <published>2016-04-02T00:00:00+00:00</published>
   <updated>2016-04-02T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Business"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2016/04/02/roles-on-software-teams/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I currently work at a software startup and wear a lot of hats. Here are some of the hats I wear and some of the hats I interact with.&lt;/p&gt;

&lt;h3&gt;Product Manager&lt;/h3&gt;

&lt;p&gt;A product manager envisions new things to create.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is either a &lt;strong&gt;stakeholder proxy&lt;/strong&gt; or a &lt;strong&gt;direct stakeholder&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stakeholder Proxy&lt;/strong&gt;: Represents the desires of external stakeholders, such as customers. This is an outbound role.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct Stakeholder&lt;/strong&gt;: Represents the desires of internal stakeholders, such as the engineering team. This is an inbound role.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Has an &lt;strong&gt;area of focus&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Discovers or envisions &lt;strong&gt;new items&lt;/strong&gt; (within the stakeholder&amp;rsquo;s area of focus).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prioritizes&lt;/strong&gt; items (within the stakeholder&amp;rsquo;s area of focus).&lt;/li&gt;
&lt;li&gt;Talks with the relevant Project Manager to get items scheduled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advocates&lt;/strong&gt; for one&amp;rsquo;s items and area of focus.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Project Manager&lt;/h3&gt;

&lt;p&gt;A project manager schedules things to be created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knows what all the &lt;strong&gt;items&lt;/strong&gt; in the backlog are.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Story&lt;/strong&gt;: A particular small outcome that is meaningful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Epic&lt;/strong&gt;: A large outcome. Associated with a collection of Stories.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Specifying Epic&lt;/strong&gt;: Generates new Stories.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Characterizing Epic&lt;/strong&gt;: Groups together existing Stories.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Area of Focus&lt;/strong&gt;: Typically a product. Sometimes a special initiative.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Knows, for each area of focus or important stakeholder, the &lt;strong&gt;relative priority&lt;/strong&gt; of items.

&lt;ul&gt;
&lt;li&gt;Talks with Product Managers to obtain relative priorities.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Decides on the &lt;strong&gt;absolute priority&lt;/strong&gt; of items, balancing different areas of focus and stakeholders.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Costs&lt;/strong&gt; items (indirectly).

&lt;ul&gt;
&lt;li&gt;Talks with Engineers to obtain costs.&lt;/li&gt;
&lt;li&gt;Negotiates with Engineers and Product Managers to obtain valuable features with reasonable time cost in a timely manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schedules&lt;/strong&gt; items to releases and &lt;strong&gt;assigns&lt;/strong&gt; items to Engineers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitors progress&lt;/strong&gt; of items, looking for slippage.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Engineer&lt;/h3&gt;

&lt;p&gt;An engineer directly creates new things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Breaks down&lt;/strong&gt; items to smaller items.

&lt;ul&gt;
&lt;li&gt;More commonly, breaks down a Story to Tasks (or &amp;ldquo;workitems&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Less commonly, reclassifies a Story as an Epic and breaks the Epic down to Stories.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Costs&lt;/strong&gt; items (directly).

&lt;ul&gt;
&lt;li&gt;Negotiates with Project Manager and/or Product Managers, perhaps splitting Stories or Epics across releases, to obtain valuable features and parts of features in a timely manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Completes stories by &lt;strong&gt;implementing&lt;/strong&gt; the associated Tasks.&lt;/li&gt;
&lt;li&gt;Is sufficiently &lt;strong&gt;skilled&lt;/strong&gt; to do any Task required for the completion of Stories they are assigned.&lt;/li&gt;
&lt;li&gt;Is familar enough with the business domain to be able to &lt;strong&gt;recognize and challenge specification errors&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;There are several kinds of engineers, which vary based on skillset:&lt;/p&gt;

&lt;h4&gt;Software Engineer (Full-Stack)&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Skilled in:

&lt;ul&gt;
&lt;li&gt;Frontend application logic. UI implementation.&lt;/li&gt;
&lt;li&gt;Backend application logic. Abstraction design.&lt;/li&gt;
&lt;li&gt;Data(base) schema design.&lt;/li&gt;
&lt;li&gt;Data(base) administration and operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Produces:

&lt;ul&gt;
&lt;li&gt;Software. Code commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;UX Engineer&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Skilled in:

&lt;ul&gt;
&lt;li&gt;Interaction design and usability.&lt;/li&gt;
&lt;li&gt;Graphic design. UI design.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;May also be skilled in:

&lt;ul&gt;
&lt;li&gt;UI implementation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Produces:

&lt;ul&gt;
&lt;li&gt;UI wireframes, both high-fidelity and low-fidelity.&lt;/li&gt;
&lt;li&gt;Use cases. Scenarios. Interaction designs. Given-When-Then specifications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Content Engineer&lt;/h4&gt;

&lt;p&gt;Produces content for the business domain. Skills vary depending on what the domain is.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Curriculum Engineer&lt;/strong&gt; - Designs and writes curriculum to teach kids.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writer&lt;/strong&gt; - Plans and writes long-form compositions such as technical documentation, manuals, blog posts, or books.&lt;/li&gt;
&lt;/ul&gt;


&lt;!-- This section is not very well thought out, mostly irrelevant to software, and is distracting from the main points. Omit. --&gt;


&lt;!--

### Operator

An operator completes tasks within a predetermined framework. An operator does not generally create new things outside that framework. Although this may sound limiting, many types of operators are highly skilled.

Software teams don't typically have many operators since they primarily focus on creating new things. Therefore most work that could be performed by a dedicated operator is usually performed by an engineer instead.

Examples of operators inside software teams, when full-stack engineers are not available:

* Database Administrator
    - Assists engineers in database schema design.
    - Assists engineers in optimizing database queries.
    - Ensures database server is provisioned with sufficient CPU, RAM, IOPs, and Disk for typical load.
    - Monitors database server for load changes, spikes, and other abnormalities.

Examples of operators outside software teams:

* Teachers
* Doctors. Dentists.
* Lawyers
* Accountants
* Drivers: Bus, taxi, etc
* Servers (i.e. waiters and waitresses)

--&gt;


&lt;h3&gt;Salesperson&lt;/h3&gt;

&lt;p&gt;A salesperson finds specific prospects, introduces them to products created by engineering, and converts them to customers.&lt;/p&gt;

&lt;p&gt;Sales activity helps to acquire customers.&lt;/p&gt;

&lt;h3&gt;Marketer&lt;/h3&gt;

&lt;p&gt;A marketer creates marketing content that creates general awareness for products and product categories among a target audience that contains prospects.&lt;/p&gt;

&lt;p&gt;Awareness in the target audience makes it easier for sales to convert individual prospects from the audience to customers.&lt;/p&gt;

&lt;p&gt;Marketing activity helps to acquire customers.&lt;/p&gt;

&lt;h3&gt;Support-person&lt;/h3&gt;

&lt;p&gt;A support person assists customers (and sometimes prospects) with operating products.&lt;/p&gt;

&lt;p&gt;Support activity helps to retain customers.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2015/09/13/state-of-the-union-in-programming-languages</id>
   <title>State of the Union in Programming Languages (2015)</title>
   <published>2015-09-13T00:00:00+00:00</published>
   <updated>2015-09-13T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2015/09/13/state-of-the-union-in-programming-languages/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Some programming languages are better at some tasks than others. Below I have presented my own assessment of how various languages stack up against each other for the following common classes of tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Programmer-bound&lt;/strong&gt;: Degree of expressive power. Magnitude of what you can implement with a small development staff. Affected by design simplicity, platform stability, and library availability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I/O-bound&lt;/strong&gt;: Suitedness for programs that spend most of their time performing I/O.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU-bound&lt;/strong&gt;: Suitedness for programs that spend most of their time calculating.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Additionally, some programming languages are on the rise or on the decline, for a wide variety of reasons. So I have also provided an assessment of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Platform longevity&lt;/strong&gt;: Degree to which the language is likely to attract and retain people and resources.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The rating scale is:&lt;/p&gt;

&lt;div class=&quot;sotu-colorize&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Excellent&lt;/strong&gt; (+2)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Good&lt;/strong&gt; (+1)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Okay&lt;/strong&gt; (0)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Poor&lt;/strong&gt; (-1)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fail&lt;/strong&gt; (-2)&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;h3&gt;Application Domain / General Purpose&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &amp;nbsp;                 &lt;/th&gt;
&lt;th&gt; Python        &lt;/th&gt;
&lt;th&gt; Java          &lt;/th&gt;
&lt;th&gt; C#            &lt;/th&gt;
&lt;th&gt; C             &lt;/th&gt;
&lt;th&gt; C++           &lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Programmer-bound&lt;/strong&gt;   &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;td&gt; Okay          &lt;/td&gt;
&lt;td&gt; Okay&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;    &lt;/td&gt;
&lt;td&gt; Poor          &lt;/td&gt;
&lt;td&gt; Okay&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;I/O-bound&lt;/strong&gt;          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;CPU-bound&lt;/strong&gt;          &lt;/td&gt;
&lt;td&gt; Poor          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Platform longevity&lt;/strong&gt; &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Okay&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;td&gt; Excellent&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;h3&gt;Web Domain&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &amp;nbsp;                 &lt;/th&gt;
&lt;th&gt; JavaScript&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/th&gt;
&lt;th&gt; PHP&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;       &lt;/th&gt;
&lt;th&gt; NodeJS        &lt;/th&gt;
&lt;th&gt; Ruby          &lt;/th&gt;
&lt;th&gt; Go            &lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Programmer-bound&lt;/strong&gt;   &lt;/td&gt;
&lt;td&gt; Okay&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;td&gt; Okay&lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;td&gt; Poor          &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:9&quot;&gt;&lt;a href=&quot;#fn:9&quot; rel=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Okay          &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;I/O-bound&lt;/strong&gt;          &lt;/td&gt;
&lt;td&gt; Okay?         &lt;/td&gt;
&lt;td&gt; Okay?         &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;CPU-bound&lt;/strong&gt;          &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:10&quot;&gt;&lt;a href=&quot;#fn:10&quot; rel=&quot;footnote&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;td&gt; Okay?         &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:11&quot;&gt;&lt;a href=&quot;#fn:11&quot; rel=&quot;footnote&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;td&gt; Poor          &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Platform longevity&lt;/strong&gt; &lt;/td&gt;
&lt;td&gt; Excellent&lt;sup id=&quot;fnref:12&quot;&gt;&lt;a href=&quot;#fn:12&quot; rel=&quot;footnote&quot;&gt;12&lt;/a&gt;&lt;/sup&gt; &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:13&quot;&gt;&lt;a href=&quot;#fn:13&quot; rel=&quot;footnote&quot;&gt;13&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:14&quot;&gt;&lt;a href=&quot;#fn:14&quot; rel=&quot;footnote&quot;&gt;14&lt;/a&gt;&lt;/sup&gt;      &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:15&quot;&gt;&lt;a href=&quot;#fn:15&quot; rel=&quot;footnote&quot;&gt;15&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Okay          &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;h3&gt;Other Domains&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &amp;nbsp;                 &lt;/th&gt;
&lt;th&gt; Objective-C   &lt;/th&gt;
&lt;th&gt; Haskell       &lt;/th&gt;
&lt;th&gt; Perl          &lt;/th&gt;
&lt;th&gt; Fortran       &lt;/th&gt;
&lt;th&gt; Lua           &lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Domain&lt;/strong&gt;             &lt;/td&gt;
&lt;td&gt; OS X, iOS     &lt;/td&gt;
&lt;td&gt; Academia      &lt;/td&gt;
&lt;td&gt; SysAdmin      &lt;/td&gt;
&lt;td&gt; Computation   &lt;/td&gt;
&lt;td&gt; Game Mods     &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Programmer-bound&lt;/strong&gt;   &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:16&quot;&gt;&lt;a href=&quot;#fn:16&quot; rel=&quot;footnote&quot;&gt;16&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Okay&lt;sup id=&quot;fnref:17&quot;&gt;&lt;a href=&quot;#fn:17&quot; rel=&quot;footnote&quot;&gt;17&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:18&quot;&gt;&lt;a href=&quot;#fn:18&quot; rel=&quot;footnote&quot;&gt;18&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; ?             &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;I/O-bound&lt;/strong&gt;          &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Poor&lt;sup id=&quot;fnref:19&quot;&gt;&lt;a href=&quot;#fn:19&quot; rel=&quot;footnote&quot;&gt;19&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Good?         &lt;/td&gt;
&lt;td&gt; ?             &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;CPU-bound&lt;/strong&gt;          &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Poor?         &lt;/td&gt;
&lt;td&gt; Excellent     &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; &lt;strong&gt;Platform longevity&lt;/strong&gt; &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Good&lt;sup id=&quot;fnref:20&quot;&gt;&lt;a href=&quot;#fn:20&quot; rel=&quot;footnote&quot;&gt;20&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Poor&lt;sup id=&quot;fnref:21&quot;&gt;&lt;a href=&quot;#fn:21&quot; rel=&quot;footnote&quot;&gt;21&lt;/a&gt;&lt;/sup&gt;     &lt;/td&gt;
&lt;td&gt; Good          &lt;/td&gt;
&lt;td&gt; Okay          &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;h3&gt;Other Worthy-of-Consideration Languages&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Swift&lt;/li&gt;
&lt;li&gt;Clojure - a Lisp dialect&lt;/li&gt;
&lt;li&gt;OCaml&lt;/li&gt;
&lt;li&gt;Standard ML&lt;/li&gt;
&lt;li&gt;Ada&lt;/li&gt;
&lt;li&gt;Rust&lt;/li&gt;
&lt;li&gt;Idris&lt;/li&gt;
&lt;li&gt;Forth&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Normally Good, but still leans verbose, similar to Java.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Normally Poor, based on the language design, but has a good standard library and massive corporate support for tooling.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Normally Good, but Oracle is a poor steward for the language.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;Cemented as the just-above-assembly language of all CPUs.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;Specifically JavaScript used on the frontend in a web browser.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;Is actually a Web Framework masquerading as a Programming Language.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;Normally Poor, but has a huge number of external libraries and massive corporate support for tooling around inefficiencies in the language.&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;Normally Poor, but has easiest deployment model of any web framework.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:9&quot;&gt;
&lt;p&gt;Normally Excellent, due to massive community support, but degraded by platform instability and lack of language specification, which retards tooling development.&lt;a href=&quot;#fnref:9&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:10&quot;&gt;
&lt;p&gt;Normally Poor, but has highly performant VMs due to massive corporate support.&lt;a href=&quot;#fnref:10&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:11&quot;&gt;
&lt;p&gt;Normally Poor, but has highly performant VMs due to massive corporate support.&lt;a href=&quot;#fnref:11&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:12&quot;&gt;
&lt;p&gt;Cemented as the assembly language of the web browser.&lt;a href=&quot;#fnref:12&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:13&quot;&gt;
&lt;p&gt;Normally Okay, but being propped up by cheap web hosting providers and an army of amateurs.&lt;a href=&quot;#fnref:13&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:14&quot;&gt;
&lt;p&gt;Drafts off of JavaScript&amp;rsquo;s popularity.&lt;a href=&quot;#fnref:14&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:15&quot;&gt;
&lt;p&gt;Normally Okay, but being propped up by startups.&lt;a href=&quot;#fnref:15&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:16&quot;&gt;
&lt;p&gt;Normally Okay, but has a top-class standard library.&lt;a href=&quot;#fnref:16&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:17&quot;&gt;
&lt;p&gt;Normally Good, but degraded by impenetrable documentation and pervasive speculative generality.&lt;a href=&quot;#fnref:17&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:18&quot;&gt;
&lt;p&gt;Normally Excellent, but degraded by excessive redundant syntax.&lt;a href=&quot;#fnref:18&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:19&quot;&gt;
&lt;p&gt;Normally Good, but degraded by making I/O difficult to perform.&lt;a href=&quot;#fnref:19&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:20&quot;&gt;
&lt;p&gt;Normally Okay, but is being propped up by academia.&lt;a href=&quot;#fnref:20&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:21&quot;&gt;
&lt;p&gt;Normally Fail, but lives on as a preinstalled scripting language for Linux.&lt;a href=&quot;#fnref:21&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2015/08/08/algorithms-101</id>
   <title>Algorithms 101 for Software Applications</title>
   <published>2015-08-08T00:00:00+00:00</published>
   <updated>2015-08-08T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2015/08/08/algorithms-101/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;In general I feel that deep algorithm knowledge is overrated in the software industry. In the early 90&amp;rsquo;s, one needed to know about common algorithms because you needed to actually &lt;em&gt;implement&lt;/em&gt; them. Today in the 00&amp;rsquo;s and 10&amp;rsquo;s one mainly needs to know which algorithms are appropriate to &lt;em&gt;use&lt;/em&gt;, since most common algorithms are already implemented in the standard library of modern programming languages. Therefore I would like to give a summary of the minimum that I think modern coders actually need to know to do their job effectively.&lt;/p&gt;

&lt;p&gt;All advice in this article is directly towards those who write &lt;em&gt;applications&lt;/em&gt;: primarily rich web applications, desktop applications, and server-side tools. In this context the &lt;em&gt;most&lt;/em&gt; advanced type of program you would be asked to write would be a compiler or other program transformation tool.&lt;/p&gt;

&lt;p&gt;If on the other hand you work in a low-level environments close to the hardware&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, are performing scientific calculations&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, or are regularly processing insanely large data sets&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, you will need to know more about algorithms that what I cover here.&lt;/p&gt;

&lt;h2&gt;Collections&lt;/h2&gt;

&lt;p&gt;In general the main algorithmic work you&amp;rsquo;ll be doing when writing programs will involve the use of &lt;strong&gt;collections&lt;/strong&gt; included in your language&amp;rsquo;s standard library. Collections hold values. The algorithms for manipulating these collections will also typically be included in the standard library.&lt;/p&gt;

&lt;h3&gt;Basic collections&lt;/h3&gt;

&lt;p&gt;The following kinds of &lt;strong&gt;collections&lt;/strong&gt; are so common as to be fundamental. Practically all programs involve the efficient manipulation of data stored in these collections.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;List&lt;/strong&gt; - An ordered sequence of elements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set&lt;/strong&gt; - An unordered set of elements, disallowing duplicates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map&lt;/strong&gt; - A structure that associates keys with values.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Sets and Maps in particular come in different flavors depending on what kind of ordering guarantee (if any) they provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unordered Set/Map&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Elements can be in any order.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stable Set/Map&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Elements appear in the order that they were added.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sorted Set/Map&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Elements are always sorted via either their natural ordering or
a custom comparison function.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Other useful more-advanced collections exist such as Bidirectional Maps, Counted Bags, Partitioning Bags, and Priority Queues, but they will not be considered here.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;Basic operations&lt;/h3&gt;

&lt;p&gt;All collections support &lt;strong&gt;operations&lt;/strong&gt; for adding elements, removing elements, and iterating over elements.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; However they do so at different speeds. It is important to choose the best kind of collection to use based on which operations your program will perform on it most frequently.&lt;/p&gt;

&lt;p&gt;Below are the operations that each collection type supports most efficiently, along with the operation&amp;rsquo;s speed in Big-Oh notation&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; when using the best&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; implementation available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List

&lt;ul&gt;
&lt;li&gt;Append element to end - O(1)&lt;/li&gt;
&lt;li&gt;Get element at random index - O(1)&lt;/li&gt;
&lt;li&gt;Set element at random index to new element - O(1)&lt;/li&gt;
&lt;li&gt;Iterate over all elements - O(n)&lt;/li&gt;
&lt;li&gt;Contains a specific element? - O(n)! (consider using a Set instead)&lt;/li&gt;
&lt;li&gt;Remove first occurrence of an element - O(n)! (consider using a Bag instead)&lt;/li&gt;
&lt;li&gt;Remove all occurrences of an element - O(n)! (consider using a Set instead)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set

&lt;ul&gt;
&lt;li&gt;Add element (if not already present) - O(1)†&lt;/li&gt;
&lt;li&gt;Remove element - O(1)†&lt;/li&gt;
&lt;li&gt;Contains a specific element? - O(1)†&lt;/li&gt;
&lt;li&gt;Iterate over all elements - O(n)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Map

&lt;ul&gt;
&lt;li&gt;Set value associated with key - O(1)†&lt;/li&gt;
&lt;li&gt;Get value associated with key - O(1)†&lt;/li&gt;
&lt;li&gt;Contains a specific key? - O(1)†&lt;/li&gt;
&lt;li&gt;Iterate over all key-value pairs - O(n)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;† = &lt;em&gt;Assumes using an Unordered or Stable implementation with a well-designed hash function. If using a Sorted implementation then performance degrades from O(1) to O(log(n)). If using a poor hash function then performance degrades from O(1) to as low as O(n).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Common algorithms exist for performing these operations. As mentioned previously it is rare that you will need to code such collection-manipulating algorithms manually unless you are working in a constrained environment. Instead you just need to be a smart shopper when picking a collection implementation to use from your language&amp;rsquo;s standard library.&lt;/p&gt;

&lt;h3&gt;Common collection implementations&lt;/h3&gt;

&lt;p&gt;Generally speaking the collections available in the standard library of a programming language will be include one or more of the following specific implementations, possibly using different names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Array-Based List&lt;/strong&gt; &lt;span style=&quot;color: green;&quot;&gt;(recommended)&lt;/span&gt;

&lt;ul&gt;
&lt;li&gt;O(1) amortized&lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; append&lt;/li&gt;
&lt;li&gt;O(1) random get and set&lt;/li&gt;
&lt;li&gt;But O(n) insert, remove, and prepend&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linked List&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(1) prepend&lt;/li&gt;
&lt;li&gt;O(1) append if tail pointer is tracked, otherwise O(n) append&lt;/li&gt;
&lt;li&gt;But O(n) random get, set, insert, and remove&lt;/li&gt;
&lt;li&gt;But causes memory fragmentation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Array&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(1) random get and set&lt;/li&gt;
&lt;li&gt;But does not support resizing after construction&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Linked Hash Set&lt;/strong&gt; &lt;span style=&quot;color: green;&quot;&gt;(recommended)&lt;/span&gt; - &lt;em&gt;a stable set&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;O(1) add, remove, and contains&lt;/li&gt;
&lt;li&gt;O(n) iteration in consistent (but not sorted) order&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hash Set&lt;/strong&gt; - &lt;em&gt;an unsorted set&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;O(1) add, remove, and contains&lt;/li&gt;
&lt;li&gt;O(n) iteration, but in random order&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tree Set&lt;/strong&gt; - &lt;em&gt;a sorted set&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;O(log(n)) add, remove, and contains&lt;/li&gt;
&lt;li&gt;O(n) iteration in sorted order&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Map

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Set-Based Map&lt;/strong&gt; &lt;span style=&quot;color: green;&quot;&gt;(recommended)&lt;/span&gt;

&lt;ul&gt;
&lt;li&gt;Uses an underlying set to hold the keys.&lt;/li&gt;
&lt;li&gt;O(1) get, set, and contains-key for stable and unsorted sets&lt;/li&gt;
&lt;li&gt;O(log(n)) get, set, and contains-key for sorted sets&lt;/li&gt;
&lt;li&gt;O(n) iteration and contains-value&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Association List&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Is just a list of key-value pairs.&lt;/li&gt;
&lt;li&gt;O(n) iteration and contains-value&lt;/li&gt;
&lt;li&gt;But O(n) get, set, and contain-key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here is a table of implementations for various common programming languages:&lt;/p&gt;

&lt;iframe src=&quot;/assets/2015/algorithms-101/Table.htm&quot;
  style=&quot;width: 100%; height: 21em; border: 0;&quot; &gt;&lt;/iframe&gt;


&lt;h3&gt;Sorting&lt;/h3&gt;

&lt;p&gt;The only advanced operation you commonly need to perform on a collection is to sort it.&lt;/p&gt;

&lt;p&gt;The following sorting algorithms are worth knowing about for actual use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Insertion Sort&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(n&lt;sup&gt;2&lt;/sup&gt;) average and worst case performance&lt;/li&gt;
&lt;li&gt;Usually faster in practice than other algorithms for &lt;em&gt;small&lt;/em&gt; numbers of elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merge Sort&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(n&amp;sdot;log(n)) average and worse case performance,
optimal for a comparison-based sort.&lt;/li&gt;
&lt;li&gt;Can be done on disk rather than in RAM, for very large data sets.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quicksort&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(n&amp;sdot;log(n)) average case performance&lt;/li&gt;
&lt;li&gt;But O(n&lt;sup&gt;2&lt;/sup&gt;) worst case performance&lt;/li&gt;
&lt;li&gt;But is not a stable sort&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heap Sort&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(n&amp;sdot;log(n)) average and worse case performance,
optimal for a comparison-based sort.&lt;/li&gt;
&lt;li&gt;But is not a stable sort&lt;/li&gt;
&lt;li&gt;But is complex to implement since it involves heaps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It&amp;rsquo;s also worth knowing that there are even faster sort algorithms that are not based on comparisons. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Radix Sort&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;O(w&amp;sdot;n) average and worst case performance, where w is usually a constant&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In interviews, knowing about and being able to implement merge sort, quicksort, and insertion sort has always been sufficient for me.&lt;/p&gt;

&lt;p&gt;Standard libraries vary in what specific sorting algorithms they offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python uses Timsort, a hybrid of Merge Sort and Insertion Sort.&lt;/li&gt;
&lt;li&gt;Java previously used either Merge Sort or Insertion Sort depending on the size of the input list but later switched to Timsort.&lt;/li&gt;
&lt;li&gt;Perl previously used Quicksort but later switched to Merge Sort.&lt;/li&gt;
&lt;li&gt;C++ does not mandate a particular algorithm but does specify that whatever algorithm provided will have worst case performance of O(n&amp;sdot;log(n)) or better.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Trees&lt;/h2&gt;

&lt;p&gt;Beyond collections, it&amp;rsquo;s useful to know how to both to implement tree data structures - particularly N-Ary Trees - how to traverse them, and how to manipulate them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;N-Ary Trees&lt;/strong&gt; are made of &lt;strong&gt;Nodes&lt;/strong&gt;, starting at a root node, where each node contains a list of children nodes. A node with no children is a leaf. A node can be related to another node as a child, parent, descendant, ancestor, or cousin. A node may or may not track who its parent is, depending on how it is implemented.&lt;/p&gt;

&lt;p&gt;Trees can be traversed in either &lt;strong&gt;Depth-First Order&lt;/strong&gt; or &lt;strong&gt;Breadth-First Order&lt;/strong&gt;. Most programs use Depth-First Order because it is easy to implement via recursion. Breadth First-Order traversal may be useful, however, in writing algorithms related to the shortest-path from the tree root.&lt;/p&gt;

&lt;p&gt;In interviews, I&amp;rsquo;ve found useful the ability to improvise new tree-related algorithms. For example an algorithm to find the nearest common ancestor.&lt;/p&gt;

&lt;h2&gt;Graphs&lt;/h2&gt;

&lt;p&gt;It is rare that you will need to use graphs in real-world application development except for the most demanding kinds of applications, such as compilers and program transformation tools. Therefore I will only cover them briefly here.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Graph&lt;/strong&gt; is made of &lt;strong&gt;Nodes&lt;/strong&gt; (sometimes called &amp;ldquo;vertices&amp;rdquo;) and &lt;strong&gt;Edges&lt;/strong&gt;. Edges connect pairs of nodes together. Beyond that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In a &amp;ldquo;directed&amp;rdquo; graph (or &amp;ldquo;digraph&amp;rdquo;), each edge has a head and tail. By contrast in an &amp;ldquo;undirected&amp;rdquo; graph, each edge is unoriented and just joins two nodes together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some graphs are &amp;ldquo;weighted&amp;rdquo;, meaning that nodes and/or edges are annotated with numerical weights.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some graphs are &amp;ldquo;multi-graphs&amp;rdquo;, meaning that they explicitly allow multiple edges between the same pair of nodes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Graphs are useful for representing and manipulating &lt;em&gt;connected&lt;/em&gt; structures, such as the intersections and roads on a map, the set of statements and related next-statements in source code, and the set of squares on a game board plus its neighbors.&lt;/p&gt;

&lt;p&gt;Algorithms for working with graphs are similar to those for working with trees but are more complicated, since each node in a graph can be typically be reached along multiple paths.&lt;/p&gt;

&lt;p&gt;Knowing how to traverse a graph in both Depth-First Order and Breadth-First Order without revisiting a node twice is extremely useful, both in practice and for interviews. For example how could you implement the paint bucket tool in a drawing program, coloring in a region of neighboring pixels without coloring in any pixel twice?&lt;/p&gt;

&lt;h2&gt;Odds and Ends&lt;/h2&gt;

&lt;p&gt;There are a few other miscellaneous concerns worth mentioning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Strings in many languages (Java, Python, JavaScript) are immutable. Therefore appending to a string takes O(n) time. By itself this is not a problem, however you need to be careful not to repeatedly append to a string inside a loop because then your runtime will be closer to O(n&lt;sup&gt;2&lt;/sup&gt;). Instead, append the string parts to a temporary list and then join the list together afterwards using the appropriate standard library function. That will get you back to O(n) time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing binary search in a list correctly is a lot harder than you think. The first couple of attempts in the academic literature actually had flawed algorithms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Algorithms involving array rearrangement and index manipulation are good to practice for interviews, since some interviewers ask for low-level tricky algorithms of this sort. For example the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dutch_national_flag_problem&quot;&gt;Dutch National Flag&lt;/a&gt; problem is a classic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Series
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        This article is part of the &lt;a href=&quot;/articles/2013/05/11/book-outline/&quot;&gt;Programming for Perfectionists&lt;/a&gt; series.
    &lt;/p&gt;
&lt;/div&gt;



&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Low-level environments typically lack rich standard libraries. So you&amp;rsquo;re back to implementing linked lists and friends by hand.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Scientific calculations involve lots of floats, which have a host of additional considerations to worry about. Chiefly float imprecision and numerical stability. The data sets involved are also typically very large.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Web services that have the popularity of Facebook, Amazon, Apple, Microsoft, or Google are dealing with unbelievable data volumes that merit using specialized algorithms. Other websites, although perhaps still popular, don&amp;rsquo;t receive anywhere near the same level of traffic.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;Further, other useful more-advanced non-collection data structures exist such as Trees, Directed Graphs, and Undirected Graphs, but they also will not be covered here.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;The runtimes quoted here are for operations that are performed &lt;em&gt;in-place&lt;/em&gt;, modifying the original collection value. If you require operations that efficiently return modified copies of the original collection, look into &lt;a href=&quot;https://en.wikipedia.org/wiki/Persistent_data_structure&quot;&gt;persistent data structures&lt;/a&gt;, such as used by &lt;a href=&quot;http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey&quot;&gt;Rich Hickey&lt;/a&gt; in the Clojure standard library.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;In Big-Oh notation, O(1) is a constant amount of time, O(log(n)) is time proportional to the order of magnitude of the collection&amp;rsquo;s size, and O(n) is time proportional to the size of the collection. Other common runtimes include O(n&amp;sdot;log(n)) and O(n&lt;sup&gt;2&lt;/sup&gt;).&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;Considerably worse performance can result if you use a poor implementation. For example if you attempt to &lt;em&gt;append&lt;/em&gt; (not prepend) an element to a list in a functional language that uses the default singly-linked list implementation, it will take O(n) time rather than the usual O(1) amortized time.&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;O(1) amortized time means that &lt;em&gt;in aggregate&lt;/em&gt; the per-operation time cost will average out to O(1). However individual operations may take O(1) in the average case or O(n) in the worst case.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2015/06/27/unicode-101</id>
   <title>Unicode 101</title>
   <published>2015-06-27T00:00:00+00:00</published>
   <updated>2015-06-27T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2015/06/27/unicode-101/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Handling international and Unicode text correctly in modern programming languages remains a poorly understood topic.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2015/06/27/unicode-101/&quot;&gt;Read more&amp;hellip;&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2015/04/26/optional-structural-static-typing-in-python</id>
   <title>Optional Structural Static Typing in Python</title>
   <published>2015-04-26T00:00:00+00:00</published>
   <updated>2015-04-26T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2015/04/26/optional-structural-static-typing-in-python/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I&amp;rsquo;m working on a new project to build a typechecking linter for Python, in the same vein as &lt;a href=&quot;http://www.mypy-lang.org&quot;&gt;mypy&lt;/a&gt;. The big difference between mypy and what I&amp;rsquo;m hoping to build is that my type system will be a &lt;em&gt;structural&lt;/em&gt; type system rather than a &lt;em&gt;nominal&lt;/em&gt; type system.&lt;/p&gt;

&lt;h2&gt;Structural vs. Nominal Type Systems&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s consider the following program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;interface Foo { public int length(); }
interface Bar { public int length(); }

Foo foo = ...
Bar bar = foo;   // Will this work?
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In a structural type system (ex: Go, OCaml) the assignment would be allowed because both interfaces have exactly the same set of methods.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; If it looks like a duck then it &lt;em&gt;is&lt;/em&gt; a duck.&lt;/p&gt;

&lt;p&gt;In a nominal type system (ex: Java, C#) the assignment would be rejected because there is no declared subtype relationship between the names &lt;code&gt;Foo&lt;/code&gt; and &lt;code&gt;Bar&lt;/code&gt;. The actual &lt;em&gt;structure&lt;/em&gt; of the interfaces is completely ignored.&lt;/p&gt;

&lt;h2&gt;Why not Nominal Typing?&lt;/h2&gt;

&lt;p&gt;It generally requires explicit type annotations for all function parameters, and sometimes function return types too. I don&amp;rsquo;t want to write &lt;em&gt;any&lt;/em&gt; type annotations for the majority of programs that I write, and certainly not annotations for every single function.&lt;/p&gt;

&lt;p&gt;There is a serious risk that Python code written with a nominal type system in mind will start introducing large numbers of new abstract base classes for the &lt;em&gt;sole&lt;/em&gt; purpose of making the typechecker happy. This is exactly the kind of pollution that I&amp;rsquo;m trying to escape from when working in dynamic languages such as Python.&lt;/p&gt;

&lt;h2&gt;Why Structural Typing?&lt;/h2&gt;

&lt;p&gt;The philosophy behind structural typing meshes a lot better with the &amp;ldquo;duck typing&amp;rdquo; that you see in classic Python with no type annotations. If you try to invoke a method on an object and the object has a method with a matching name, the program will work. This is exactly the properly that a structural type system checks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Loosely defined protocols such as &amp;ldquo;file-like objects&amp;rdquo; continue to work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More complex protocols such as &amp;ldquo;file-like objects that support fileno()&amp;rdquo; (as needed by the &lt;code&gt;subprocess&lt;/code&gt; module) also work without needing to introduce further abstract base classes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lightweight JSON-based objects continue to work and benefit from type checking.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;More importantly, structural type systems are much more amenable to global type inference, which can be used to eliminate the need for explicit type annotations. This would allow Python programs to still be type-checked without the need to specify type annotations in the usual case. Imagine if your programs &lt;em&gt;today&lt;/em&gt;, without any type annotations, could suddenly become type checked with no additional effort from you, the programmer.&lt;/p&gt;

&lt;h2&gt;Challenges with Structural Typing&lt;/h2&gt;

&lt;p&gt;Of course structural typing isn&amp;rsquo;t all good. It has one major sticking point: Structural type systems tend to generate huge verbose error messages that aren’t particularly actionable.&lt;/p&gt;

&lt;p&gt;This happens because the type checker only knows that two (complex) inferred types are incompatible. It doesn&amp;rsquo;t know which of the two types is correct. And the error messages containing the derivation of the inferred types typically involves lots of locations in the code unrelated to where the actual error lies. Imagine the same level of verbosity as C++ template errors.&lt;/p&gt;

&lt;h2&gt;Mission: Difficult&lt;/h2&gt;

&lt;p&gt;So in summary the goal is to make a type checking linter for Python with a structural type system and global type inference which nevertheless presents comprehensible and actionable error messages in a majority of error scenarios.&lt;/p&gt;

&lt;p&gt;I see some original research in my near future.&lt;/p&gt;

&lt;h2&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=fDTt_uo0F-g&quot;&gt;Uncovering the Unknown: Principles of Type Inference&lt;/a&gt; (1h3m)

&lt;ul&gt;
&lt;li&gt;Excellent presentation outlining the difference between nominal vs. structural subtyping, typing inference, and some pros/cons between both kinds of type systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.amazon.com/Types-Programming-Languages-Benjamin-Pierce/dp/0262162091/ref=sr_1_1?ie=UTF8&amp;amp;qid=1430091478&amp;amp;sr=8-1&amp;amp;keywords=types+and+programming+languages&quot;&gt;Types and Programming Languages&lt;/a&gt; (645 pages)

&lt;ul&gt;
&lt;li&gt;Excellent broad overview of type systems and type theory. Leans toward covering type systems similar to those used in mainstream programming languages. Has only limited information about type reconstruction and type inference.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;To be more precise, the assignment would be allowed because &lt;code&gt;Foo&lt;/code&gt; structure contains everything that &lt;code&gt;Bar&lt;/code&gt; requires: the methods on &lt;code&gt;Bar&lt;/code&gt; are a subset of the methods on &lt;code&gt;Foo&lt;/code&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2015/03/14/semantic-versioning-vs-romantic-versioning</id>
   <title>Semantic Versioning vs. Romantic Versioning</title>
   <published>2015-03-14T00:00:00+00:00</published>
   <updated>2015-03-14T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2015/03/14/semantic-versioning-vs-romantic-versioning/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;In recent years the larger software development community has started to pay more attention to version numbers.&lt;/p&gt;

&lt;h2&gt;Semantic Versioning&lt;/h2&gt;

&lt;p&gt;The Node community in particular has introduced specific guidelines for what it means when you increment various parts of a version number. Generally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A version number is a 3-part value &lt;strong&gt;X.Y.Z&lt;/strong&gt; where &lt;strong&gt;X, Y&lt;/strong&gt;, and &lt;strong&gt;Z&lt;/strong&gt; are the &lt;strong&gt;major&lt;/strong&gt;, &lt;strong&gt;minor&lt;/strong&gt;, and &lt;strong&gt;patch&lt;/strong&gt; components respectively.&lt;/li&gt;
&lt;li&gt;When making a new release that contains &lt;strong&gt;bug fixes only&lt;/strong&gt;, you may increment the patch component.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X.Y.Z -&amp;gt; X.Y.(Z+1)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When making a new release that contains &lt;strong&gt;new features&lt;/strong&gt; (and possibly some bug fixes) but not breaking changes, you may increment the minor component (and reset the patch component to zero).

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X.Y.Z -&amp;gt; X.(Y+1).0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When making a new release that contains &lt;strong&gt;breaking changes&lt;/strong&gt; (and possibly some new features or bug fixes), you may increment the major component (and reset both the minor and patch components to zero).

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X.Y.Z -&amp;gt; (X+1).0.0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This scheme for version numbering, called &lt;strong&gt;&lt;a href=&quot;http://semver.org&quot;&gt;semantic versioning&lt;/a&gt;&lt;/strong&gt; (or SemVer), is easy for automatic dependency management systems to understand, making it highly useful for communities that encourage liberal use of third-party libraries.&lt;/p&gt;

&lt;h3&gt;When to use Semantic Versioning&lt;/h3&gt;

&lt;p&gt;Use of semantic versioning is highly recommended for projects that are intended to be depended on and automatically upgraded, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;libraries&lt;/strong&gt; (ex: jQuery, Underscore, requests, libxml2).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Semantic versioning is also useful for slower-moving projects that may require some manual upgrade steps, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;frameworks&lt;/strong&gt; (ex: Django, Ruby on Rails, Spring);&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;language platforms&lt;/strong&gt; (Java, C#, Python, Ruby);&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;runtime platforms&lt;/strong&gt; (ex: JVM, CLR, CPython, MRI); and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OS platforms&lt;/strong&gt; (ex: OS X, Windows, Debian).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Using semantic versioning makes it easy for high-level projects to regularly upgrade their lower-level dependencies, either automatically or manually.&lt;/p&gt;

&lt;h2&gt;Romantic Versioning&lt;/h2&gt;

&lt;p&gt;By contrast, I use the term &lt;strong&gt;romantic versioning&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; to refer to all other version numbering schemes that adhere to the following fuzzy guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A version number is a multi-part value such as &lt;strong&gt;X&lt;/strong&gt;, &lt;strong&gt;X.Y&lt;/strong&gt;, or &lt;strong&gt;X.Y.Z&lt;/strong&gt;; with numeric components.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;conceptually&lt;/em&gt; major change bumps the first component of the value.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;conceptually&lt;/em&gt; minor change or bug fix bumps a later component of the value.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Romantic versioning is meant primarily for &lt;em&gt;humans&lt;/em&gt; to understand, at the possible expense of easy understanding by a computer. This makes it suitable for marketing purposes (since marketing is directed at humans) but often not suitable for automated dependency management (which is performed by a computer).&lt;/p&gt;

&lt;h3&gt;When to use Romantic Versioning&lt;/h3&gt;

&lt;p&gt;As mentioned before, romantic versioning is mainly suitable for projects that are actively marketed and updated over time but not depended on by other projects, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;applications&lt;/strong&gt; (Microsoft Word, Firefox, Spotify, Evernote).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Some projects are not updated over time (such as many console games) and so have no version number at all.&lt;/p&gt;

&lt;h2&gt;Hybrid Romantic &amp;amp; Semantic Versioning&lt;/h2&gt;

&lt;p&gt;There are many projects that maintain two different version numbers simultaneously: a romantic version for marketing purposes and a semantic version for developer purposes. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java

&lt;ul&gt;
&lt;li&gt;Currently at &amp;ldquo;product version&amp;rdquo; &lt;code&gt;8.40&lt;/code&gt; (&amp;ldquo;Java SE 8u40&amp;rdquo;), which is the romantic version; and &amp;ldquo;developer version&amp;rdquo; &lt;code&gt;1.8.40&lt;/code&gt;, which is the semantic version.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Windows

&lt;ul&gt;
&lt;li&gt;At marketing version &lt;code&gt;7&lt;/code&gt; (&amp;ldquo;Windows 7&amp;rdquo;), which is the romantic version; and at internal version &lt;code&gt;6.1&lt;/code&gt;, which is the best approximation of its semantic version.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;There are also some libraries that advertise a romantic version as if it were a semantic version which causes &lt;a href=&quot;https://github.com/jashkenas/underscore/issues/1805&quot;&gt;lots of problems&lt;/a&gt; when automated dependency management systems try to consume the library.&lt;/p&gt;

&lt;h2&gt;Final Observations&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Projects typically&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; have a &lt;strong&gt;romantic version&lt;/strong&gt;, a &lt;strong&gt;semantic version&lt;/strong&gt;, or both.&lt;/li&gt;
&lt;li&gt;Applications tend to have a &lt;strong&gt;romantic version&lt;/strong&gt; only, since they are marketed to consumers rather than developers.&lt;/li&gt;
&lt;li&gt;Libraries tend to have a &lt;strong&gt;semantic version&lt;/strong&gt; only, since they are used only by automated tooling and developers.&lt;/li&gt;
&lt;li&gt;Other types of projects like frameworks and platforms have more variation, often providing both a romantic and semantic version since they are often both marketed to consumers and used by developers.&lt;/li&gt;
&lt;/ul&gt;


&lt;hr /&gt;

&lt;p&gt;Enjoy this article? Follow my &lt;a href=&quot;https://twitter.com/davidfstr&quot;&gt;Twitter account&lt;/a&gt; for notifications of new articles. 😃&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes programming languages and their unique features.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/20/visual-guide-to-programming-language-properties/&quot;&gt;Visual Guide to Programming Language Properties&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Visualizes how various programming language properties interact.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;I have seen other people use different terms to refer to &lt;strong&gt;romantic versioning&lt;/strong&gt;. For example Dominic Tarr calls such versioning schemes &lt;a href=&quot;http://sentimentalversioning.org&quot;&gt;&amp;ldquo;sentimental versioning&amp;rdquo;&lt;/a&gt;. However he mainly mocks such schemes, highlighting the negative aspects of romantic versioning as perceived by a developer without considering the positive aspects for marketing to consumers.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Projects that receive no updates are &lt;strong&gt;unversioned&lt;/strong&gt;, with no version number, such as many console games. And a small number of projects use an &lt;strong&gt;esoteric versioning&lt;/strong&gt; scheme, with version numbers that are hard to interpret by either human or computer. For example successive version numbers of &lt;a href=&quot;https://en.wikipedia.org/wiki/TeX&quot;&gt;TeX&lt;/a&gt; are closer and closer approximations of π.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2015/02/27/proof-terms-in-idris</id>
   <title>Proof terms in Idris</title>
   <published>2015-02-27T00:00:00+00:00</published>
   <updated>2015-02-27T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2015/02/27/proof-terms-in-idris/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Recently I&amp;rsquo;ve been experimenting with the language &lt;a href=&quot;http://www.idris-lang.org&quot;&gt;Idris&lt;/a&gt;, one of the rare &lt;strong&gt;dependently-typed&lt;/strong&gt; programming languages.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; For example you can write a sorting function that is proven correct by the compiler at &lt;em&gt;compile time&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sort : (inputList:Vect n e) -&amp;gt; 
       (outputList:Vect n e ** (IsSorted outputList) ** 
                               (ElemsAreEq inputList outputList))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The preceding is a function that takes an input list (or &amp;ldquo;vector&amp;rdquo;) of elements and returns a tuple containing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;an output list,&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;proof&lt;/strong&gt; that the output list is sorted (&lt;code&gt;IsSorted&lt;/code&gt;), and&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;proof&lt;/strong&gt; that the input list and output list have the same elements (&lt;code&gt;ElemsAreEq&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Since the type signature is verified at compile time, any function implementing this signature is a provably correct sort function.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The notion that a proof can be represented explicitly in a program is fascinating and a unique capability of dependently-typed languages.&lt;/p&gt;

&lt;p&gt;In this article I will focus specifically on what proof terms are, how to define them, and how to construct them.&lt;/p&gt;

&lt;p&gt;I assume that the reader has basic familiarity with Haskell-like syntax.&lt;/p&gt;

&lt;!--
To reach the widest audience possible I assume only that the reader has general programming experience, perhaps only in imperative languages with C-derived syntax. Basic familiarity with Haskell-like syntax is useful but not assumed. I will try to explain new syntax when it appears, particularly when it differs from C-style syntax.
--&gt;


&lt;h2&gt;A simple built-in proof type: &lt;code&gt;Data.So&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Proof types are tricky to grasp at first. Thus let&amp;rsquo;s start by examining the simplest proof type in the Idris standard library&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, the &lt;code&gt;So&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;Here is the definition of the &lt;code&gt;Data.So&lt;/code&gt; type:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;data So : Bool -&amp;gt; Type where 
    Oh : So True
&lt;/code&gt;&lt;/pre&gt;

&lt;!--
Syntax notes:

* Function-like things are declared with `funcName : argType1 -&gt; argType2 -&gt; returnType`.
    * In this case `So` takes a `Bool` and defines a type.
    * Thus `So` is a parameterized type, not unlike the parameterized types `List` and `IList` in Java and C# respectively, which are parameterized by their element type. So a `List&lt;String&gt;` or `IList&lt;string&gt;` is a list of strings. In Idris the same type would be written as `(List String)` (with a space) and declared as `List : e -&gt; Type`, where `e` represented the element type of the list.
* `So` is defined as a data type parameterized[^actually-indexed] by a boolean expression (of type `Bool`). You can create a type expression like `So (1 &lt; 1)` or `So (1 &gt; 2)`.
* `So` has a single type constructor `Oh` which takes no parameters. It is an atomic thing.
* You can only make an `Oh` when the boolean expression in the resultant `So (...)` type can be proven equal to `True` by the compiler at compile time.

[^actually-indexed]: Type theory buffs will probably correct me by emphasizing that types can be *parameterized* by other types but are *indexed* by values. Again I think this distinction is immaterial to the practitioner and therefore will say that a type can be parameterized by either types or values.

--&gt;


&lt;p&gt;The &lt;code&gt;So&lt;/code&gt; type represents a proof that a particular boolean test has been performed and that it evaluated to &lt;code&gt;True&lt;/code&gt;. For example it is possible to construct a proof value (&lt;code&gt;Oh&lt;/code&gt;) of type &lt;code&gt;So (1 &amp;lt; 2)&lt;/code&gt; but it is not possible to construct a value of type &lt;code&gt;So (1 &amp;gt; 2)&lt;/code&gt;.&lt;/p&gt;

&lt;!--
`Oh`? `So`? These are rather strange names, no? I personally find this type easier to understand if I think of it as:

```
data IsTrue : Bool -&gt; Type where 
    ProvablyTrue : IsTrue True
```
--&gt;


&lt;p&gt;You can construct a value of &lt;code&gt;So (1 &amp;lt; 2)&lt;/code&gt; directly on the command-line:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner
Idris&amp;gt; :module Data.So
*So&amp;gt; the (So (1 &amp;lt; 2)) Oh
Oh : So True
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The function &lt;code&gt;(the FooType fooValue)&lt;/code&gt; tells the compiler that &lt;code&gt;fooValue&lt;/code&gt; should be of type &lt;code&gt;FooType&lt;/code&gt;, which is occasionally useful. In this case I am asserting to the compiler that &lt;code&gt;So (1 &amp;lt; 2)&lt;/code&gt; is so obvious that it should just try to construct the proof value &lt;code&gt;Oh&lt;/code&gt; immediately.&lt;/p&gt;

&lt;p&gt;However you can&amp;rsquo;t make a &lt;code&gt;So (1 &amp;gt; 2)&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner
Idris&amp;gt; :module Data.So
*So&amp;gt; the (So (1 /= 1)) Oh
(input):1:5:When elaborating argument x to function Prelude.Basics.the:
        Can't unify
                So True
        with
                So (fromInteger 1 &amp;gt; fromInteger 2)

        Specifically:
                Can't unify
                        True
                with
                        fromInteger 1 &amp;gt; fromInteger 2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Here the error message indicates that the compiler isn&amp;rsquo;t convinced that &lt;code&gt;True == (1 &amp;gt; 2)&lt;/code&gt;, which is absolutely correct.&lt;/p&gt;

&lt;p&gt;In a real program the main way to construct a &lt;code&gt;So&lt;/code&gt; is to use the &lt;code&gt;choose&lt;/code&gt; function, whose definition is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;choose : (b : Bool) -&amp;gt; Either (So b) (So (not b))
choose True  = Left Oh
choose False = Right Oh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You might have to stare at this definition for a while to understand how it works. I know it took me a while to grok it. Let me try to explain:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;choose&lt;/code&gt; function is performing a pattern match on the &lt;code&gt;Bool&lt;/code&gt; argument it receives. If it successfully pattern matches on &lt;code&gt;True&lt;/code&gt;, the compiler itself understands that argument &lt;code&gt;b&lt;/code&gt; is equivalent to &lt;code&gt;True&lt;/code&gt;, so it permits the construction of the value &lt;code&gt;Oh&lt;/code&gt; (of type &lt;code&gt;So b&lt;/code&gt;) on the right-hand-side of the &lt;code&gt;choose True&lt;/code&gt; definition. The &lt;code&gt;choose False&lt;/code&gt; definition works via similar reasoning to construct a value &lt;code&gt;Oh&lt;/code&gt; of type &lt;code&gt;So (not b)&lt;/code&gt;, since the compiler can deduce that &lt;code&gt;not b&lt;/code&gt; is &lt;code&gt;True&lt;/code&gt; when &lt;code&gt;b&lt;/code&gt; is &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;A simple derived proof type: &lt;code&gt;IsLte&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;What if we wanted to prove specifically that one element is less than or equal to another? We could write a proof type derived directly from &lt;code&gt;Data.So&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;formula-box&quot;&gt;&lt;pre&gt;&lt;code&gt;IsLte : Ord e =&amp;gt; (x:e) -&amp;gt; (y:e) -&amp;gt; Type
IsLte x y = So (x &amp;lt;= y)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;




&lt;!--
Syntax notes:

* `Ord e` is a type constraint on `e` which requires that elements of type `e` implement a comparison function, so that expressions like `x &lt;= y` can work (where `x` and `y` are of type `e`).
    * In Java the equivalent constaint is implemented by the interface `Comparable`, and in C# it is `IComparable`.
--&gt;


&lt;p&gt;Here the &lt;code&gt;IsLte&lt;/code&gt; type is defined directly in terms of the &lt;code&gt;So&lt;/code&gt; proof type that was described previously. Note that it is necessary to add the &lt;code&gt;Ord e&lt;/code&gt; type constraint so that the compiler will allow the use of &lt;code&gt;&amp;lt;=&lt;/code&gt; to compare &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; in &lt;code&gt;(x &amp;lt;= y)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Strictly speaking the definition of &lt;code&gt;IsLte&lt;/code&gt; here doesn&amp;rsquo;t create a new type, but rather a type alias to the underlying &lt;code&gt;So&lt;/code&gt;. Therefore you must use the &lt;code&gt;Oh&lt;/code&gt; proof value to actually make an &lt;code&gt;IsLte&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner IsLte.idr 
*IsLte&amp;gt; the (IsLte 1 2) Oh
Oh : So True
*IsLte&amp;gt; the (IsLte 2 1) Oh
(input):1:5:When elaborating argument x to function Prelude.Basics.the:
        Can't unify
                So True
        with
                IsLte (fromInteger 2) (fromInteger 1)

        Specifically:
                Can't unify
                        True
                with
                        fromInteger 2 &amp;lt;= fromInteger 1
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now it&amp;rsquo;s fine and all to create a &lt;code&gt;So&lt;/code&gt; or &lt;code&gt;IsLte&lt;/code&gt; directly on the command line. But how would you create one in an actual program?&lt;/p&gt;

&lt;div class=&quot;formula-box&quot;&gt;&lt;pre&gt;&lt;code&gt;mkIsLte : Ord e =&amp;gt; (x:e) -&amp;gt; (y:e) -&amp;gt; Maybe (IsLte x y)
mkIsLte x y =
    case (choose (x &amp;lt;= y)) of 
        Left proofXLteY =&amp;gt;
            Just proofXLteY
        Right proofNotXLteY =&amp;gt;
            Nothing
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;




&lt;!--
Syntax notes:

* The `choose` function here is the same one mentioned before that operates on `So` types, which works here because an `IsLte` is actually a `So`.
* The `case...of` statement is like a fancy switch statement: It does pattern matching to determine which branch to take.
* Notice the use of the naming convention `proof...` for proof values. Having longish descriptive names for proof values really helps in more complex code that has a lot of proof values.
--&gt;


&lt;p&gt;This function takes an &lt;code&gt;x&lt;/code&gt; and a &lt;code&gt;y&lt;/code&gt; at runtime and constructs a proof value of type &lt;code&gt;(IsLte x y)&lt;/code&gt; if x &amp;lt;= y. If x is not &amp;lt;= y then it fails by returning a &lt;code&gt;Nothing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the Idris CLI, let&amp;rsquo;s try to construct a valid proof that &lt;code&gt;(IsLte 1 2)&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner InsertionSort.idr
*InsertionSort&amp;gt; mkIsLte 1 2
Just Oh : Maybe (So True)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Nice. How about a proof that &lt;code&gt;(IsLte 2 1)&lt;/code&gt;?&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner InsertionSort.idr
*InsertionSort&amp;gt; mkIsLte 2 1
Nothing : Maybe (So False)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Fails as expected.&lt;/p&gt;

&lt;h2&gt;A simple standalone proof type: &lt;code&gt;HeadIs&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s implement our own simple proof type. How about a proof that a vector begins with a particular value?&lt;/p&gt;

&lt;div class=&quot;formula-box&quot;&gt;&lt;pre&gt;&lt;code&gt;data HeadIs : Vect n e -&amp;gt; e -&amp;gt; Type where
    MkHeadIs : HeadIs (x::xs) x
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;




&lt;!--
Syntax notes:

* `Vect n e` represents a list (or &quot;vector&quot;) of length `n` containing elements of type `e`.
* Regarding vectors:
    * `Nil` is the empty vector. It can also be written as `[]` in some contexts.
    * The operator `::` in `x::xs` takes an element `x` and prepends it to a vector `xs` returning a new vector `x::xs` with the prepended element.
        * Most functional languages define **prepend** as the more basic operation than **append**, in contrast to most imperative languages.
    * The first element of a vector is called the &quot;head&quot;. The remainder is called the &quot;tail&quot;.
* Regarding naming conventions:
    * `x`, `y`, and `z` will be used to refer to elements in vectors.
    * `xs`, `ys`, and `zs` will be used to refer to vectors.
    * `n` will be used to refer to the length of a vector.
--&gt;


&lt;p&gt;A value of type &lt;code&gt;HeadIs xs y&lt;/code&gt; represents a proof that a vector &lt;code&gt;xs&lt;/code&gt; begins with (&amp;ldquo;has the head&amp;rdquo;) &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Based on the definition above, the compiler will only permit the construction of the atomic &lt;code&gt;MkHeadIs&lt;/code&gt; proof value if it can destructure its first vector argument and see that its head matches the second argument.&lt;/p&gt;

&lt;h2&gt;A complex proof type: &lt;code&gt;IsSorted&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;How about we try to make a more complex proof type? How about a proof that a list of elements is sorted? Such a proof type would be useful in the &lt;code&gt;sort&lt;/code&gt; function mentioned at the beginning of this article.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s take a first stab at thinking about the initial signature of &lt;code&gt;IsSorted&lt;/code&gt;. We want to be able to write &lt;code&gt;IsSorted xs&lt;/code&gt;, so we need &lt;code&gt;IsSorted&lt;/code&gt; to take a vector &lt;code&gt;xs&lt;/code&gt; argument and return a type:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;data IsSorted : (xs:Vect n e) -&amp;gt; Type where
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay. Now, since proof terms work entirely by pattern matching on the arguments received, let&amp;rsquo;s think about what cases exist for matching on the single &lt;code&gt;xs&lt;/code&gt; vector argument:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Nil&lt;/code&gt; &amp;ndash; Definitely sorted, since it&amp;rsquo;s an empty vector. &lt;strong&gt;(Case 1)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x::xs&lt;/code&gt; &amp;ndash; Not enough information to determine whether sorted. Let&amp;rsquo;s decompose &lt;code&gt;xs&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x::Nil&lt;/code&gt; &amp;ndash; Definitely sorted, since it&amp;rsquo;s a vector with only one element. &lt;strong&gt;(Case 2A)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x::(y::ys)&lt;/code&gt; &amp;ndash; Sorted if: &lt;strong&gt;(Case 2B)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;(1) we can prove &lt;code&gt;(x &amp;lt;= y)&lt;/code&gt; and that&lt;/li&gt;
&lt;li&gt;(2) &lt;code&gt;(y::ys)&lt;/code&gt; is sorted.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So let&amp;rsquo;s write out the preceding cases in code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;data IsSorted : (xs:Vect n e) -&amp;gt; Type where
    IsSortedZero :
        ... -&amp;gt;
        IsSorted Nil
    IsSortedOne  :
        ... -&amp;gt;
        IsSorted (x::Nil)
    IsSortedMany :
        ... -&amp;gt;
        IsSorted (x::(y::ys))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Straightforward. Now let&amp;rsquo;s fill in the holes for the parameter types:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;data IsSorted : (xs:Vect n e) -&amp;gt; Type where
    IsSortedZero :
        IsSorted Nil
    IsSortedOne  :
        (x:e) -&amp;gt;
        IsSorted (x::Nil)
    IsSortedMany :
        (x:e) -&amp;gt; (y:e) -&amp;gt; (ys:Vect n'' e) -&amp;gt;     -- (n'' == (n - 2))
        (IsLte x y) -&amp;gt; IsSorted (y::ys) -&amp;gt;
        IsSorted (x::(y::ys))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;IsSortedZero&lt;/code&gt; case didn&amp;rsquo;t require any parameters at all. Easy enough.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;IsSortedOne&lt;/code&gt; case had only the variable &lt;code&gt;x&lt;/code&gt; in its return type, so we just need to declare the parameter &lt;code&gt;(x:e)&lt;/code&gt; so that it knew what &lt;code&gt;x&lt;/code&gt; to use.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;IsSortedMany&lt;/code&gt; case is a lot more interesting:

&lt;ul&gt;
&lt;li&gt;It needs the three &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;ys&lt;/code&gt; objects that appear in the return type &lt;code&gt;(x::(y::ys))&lt;/code&gt; to be defined.&lt;/li&gt;
&lt;li&gt;It needs a proof that &lt;code&gt;x &amp;lt;= y&lt;/code&gt;. So let&amp;rsquo;s use an &lt;code&gt;(IsLte x y)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It needs a proof that &lt;code&gt;y::ys&lt;/code&gt; is sorted, so let&amp;rsquo;s recursively use the &lt;code&gt;IsSorted&lt;/code&gt; proof type that we&amp;rsquo;re in the middle of defining!

&lt;ul&gt;
&lt;li&gt;Yay recursively defined types. Just like recursively defined functions. And sometimes just as mind-bending.&lt;/li&gt;
&lt;li&gt;I believe Idris will only allow recursive definitions of types in this way because the compiler itself can determine that the &lt;code&gt;IsSorted (y::ys)&lt;/code&gt; proof type is &amp;ldquo;smaller than&amp;rdquo; the &lt;code&gt;IsSorted (x::(y::ys))&lt;/code&gt; proof type whose definition it feeds into.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Let&amp;rsquo;s try to compile this:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris -o Scratch Scratch.idr 
Scratch.idr:17:18:When elaborating type of Main.IsSortedMany:
Can't resolve type class Ord e
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Whoops. The &lt;code&gt;IsSortedMany&lt;/code&gt; definition doesn&amp;rsquo;t know what to fill in for the implicit &lt;code&gt;Ord e&lt;/code&gt; parameter to the &lt;code&gt;IsLte&lt;/code&gt; type. So let&amp;rsquo;s add that parameter to &lt;code&gt;IsSortedMany&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;data IsSorted : (xs:Vect n e) -&amp;gt; Type where
    IsSortedZero :
        IsSorted Nil
    IsSortedOne  :
        (x:e) -&amp;gt;
        IsSorted (x::Nil)
    IsSortedMany :
        Ord e =&amp;gt;
        (x:e) -&amp;gt; (y:e) -&amp;gt; (ys:Vect n'' e) -&amp;gt;    -- (n'' == (n - 2))
        (IsLte x y) -&amp;gt; IsSorted (y::ys) -&amp;gt;
        IsSorted (x::(y::ys))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now this actually compiles and I could stop here. However I know based on painful experience&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; that we will run into type unification errors down the road if we don&amp;rsquo;t additionally put the &lt;code&gt;Ord e&lt;/code&gt; constraint on the &lt;code&gt;IsSorted&lt;/code&gt; type itself. So let&amp;rsquo;s just do that:&lt;/p&gt;

&lt;div class=&quot;formula-box&quot;&gt;&lt;pre&gt;&lt;code&gt;data IsSorted : Ord e =&amp;gt; (xs:Vect n e) -&amp;gt; Type where
    IsSortedZero :
        Ord e =&amp;gt;
        IsSorted Nil
    IsSortedOne  :
        Ord e =&amp;gt;
        (x:e) -&amp;gt;
        IsSorted (x::Nil)
    IsSortedMany :
        Ord e =&amp;gt; 
        (x:e) -&amp;gt; (y:e) -&amp;gt; (ys:Vect n'' e) -&amp;gt;    -- (n'' == (n - 2))
        (IsLte x y) -&amp;gt; IsSorted (y::ys) -&amp;gt;
        IsSorted (x::(y::ys))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Boom. Done.&lt;/p&gt;

&lt;p&gt;Now, similar to the &lt;code&gt;mkIsLte&lt;/code&gt; function from before, let&amp;rsquo;s create a &lt;code&gt;mkIsSorted&lt;/code&gt; function that, given a list, checks whether it is sorted and returns an &lt;code&gt;IsSorted&lt;/code&gt; sortedness proof if it is.&lt;/p&gt;

&lt;div class=&quot;formula-box&quot;&gt;&lt;pre&gt;&lt;code&gt;mkIsSorted : Ord e =&amp;gt; (xs:Vect n e) -&amp;gt; Maybe (IsSorted xs)
mkIsSorted Nil =
    Just IsSortedZero
mkIsSorted (x::Nil) =
    Just (IsSortedOne x)
mkIsSorted (x::(y::ys)) =
    case (mkIsLte x y) of
        Just proofXLteY =&amp;gt;
            case (mkIsSorted (y::ys)) of
                Just proofYYsIsSorted =&amp;gt;
                    Just (IsSortedMany x y ys proofXLteY proofYYsIsSorted)
                Nothing =&amp;gt;
                    Nothing
        Nothing =&amp;gt;
            Nothing
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This implementation is interesting. Note how the proof values &lt;code&gt;IsSortedZero&lt;/code&gt;, &lt;code&gt;IsSortedOne&lt;/code&gt;, and &lt;code&gt;IsSortedMany&lt;/code&gt; are constructed directly.&lt;/p&gt;

&lt;p&gt;Also notice in particular that to construct an &lt;code&gt;IsSortedMany&lt;/code&gt; value that the subproof values &lt;code&gt;proofXLteY&lt;/code&gt; and &lt;code&gt;proofYYsIsSorted&lt;/code&gt; needed to be constructed first. And that the latter subproof required a recursive invocation of &lt;code&gt;mkIsSorted&lt;/code&gt;. Lots of recursion in Idris.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s try calling the function with a valid sorted list:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner InsertionSort.idr
*InsertionSort&amp;gt; mkIsSorted [1,2,3]
Just (IsSortedMany 1
                   2
                   [3]
                   Oh
                   (IsSortedMany 2
                                 3
                                 []
                                 Oh
                                 (IsSortedOne 3))) : Maybe (IsSorted [1, 2, 3])
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Nice. See how the proof term embeds the &lt;code&gt;(IsLte 1 2)&lt;/code&gt; and &lt;code&gt;(IsLte 2 3)&lt;/code&gt; values (both &lt;code&gt;Oh&lt;/code&gt;) which represent the comparison checks made to determine whether the list was sorted. In this fashion a proof value effectively embeds an execution trace of the program that generated it. Neato.&lt;/p&gt;

&lt;p&gt;We can generalize this observation: The contents of a big proof value is a nested structure of smaller proof values that taken together are used to derive the big proof value. Here, an &lt;code&gt;IsSorted [1,2,3]&lt;/code&gt; value contains both an &lt;code&gt;IsLte 1 2&lt;/code&gt; and an &lt;code&gt;IsLte 2 3&lt;/code&gt; value, which is enough to deduce that &lt;code&gt;[1,2,3]&lt;/code&gt; is sorted.&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s try calling &lt;code&gt;mkIsSorted&lt;/code&gt; with a non-sorted list:&lt;/p&gt;

&lt;div class=&quot;terminal-box&quot;&gt;&lt;pre&gt;&lt;code&gt;$ idris --nobanner InsertionSort.idr
*InsertionSort&amp;gt; mkIsSorted [3,2,1]
Nothing : Maybe (IsSorted [3, 2, 1])
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;As expected, we couldn&amp;rsquo;t construct a proof that an unsorted list was actually sorted.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Hopefully you now have a better grasp of proof types and values, and also have some practice in constructing them.&lt;/p&gt;

&lt;p&gt;In an upcoming article I hope to demonstrate how proof types like &lt;code&gt;IsSorted&lt;/code&gt; and &lt;code&gt;ElemsAreEq&lt;/code&gt; can be used to create a provably correct implementation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Insertion_sort&quot;&gt;insertion sort&lt;/a&gt;. Stay tuned.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;http://wiki.portal.chalmers.se/agda/pmwiki.php&quot;&gt;Agda&lt;/a&gt; is another dependently typed language that I&amp;rsquo;ve looked at. However I was &lt;a href=&quot;/articles/2014/02/17/agda-second-impressions/&quot;&gt;not impressed&lt;/a&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;p&gt;Actually to prove the correctness of the &lt;code&gt;sort&lt;/code&gt; function you need to verify one more thing in addition to the function signature: You must verify that the definitions of the related proof types (in this case &lt;code&gt;IsSorted&lt;/code&gt; and &lt;code&gt;ElemsAreEq&lt;/code&gt;) correctly implement what their name implies.&lt;/p&gt; &lt;p&gt;Usually the definitions of proof types are fairly compact so inspection isn&amp;rsquo;t much of a burden. By contrast the correct &lt;em&gt;construction&lt;/em&gt; of proof terms within an algorithm is considerably more complex. Happily the compiler checks your work ruthlessly within the algorithm itself, so you don&amp;rsquo;t have to worry about messing up term construction.&lt;/p&gt;&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;The Idris community appears to prefer the term &amp;ldquo;the standard library&amp;rdquo; to refer specifically to the prelude part of the library code that ships with Idris and &amp;ldquo;the library&amp;rdquo; to refer to the non-prelude part. I think this distinction is unimportant and confusing so I will use the term &amp;ldquo;standard library&amp;rdquo; to refer to &lt;em&gt;all&lt;/em&gt; library code that ships with Idris, which is consistent with terminology usage in other languages (Python, Java, C#, Perl, PHP, etc).&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;In my initial attempt to define &lt;code&gt;IsSorted&lt;/code&gt; I incorrectly required only the subproof &lt;code&gt;IsSorted ys&lt;/code&gt; and not &lt;code&gt;IsSorted (y::ys)&lt;/code&gt; when proving &lt;code&gt;IsSorted x::(y::ys)&lt;/code&gt;. But that restriction allows you to construct &lt;code&gt;IsSorted [9,10,1,2]&lt;/code&gt; which is clearly bogus. Pay attention to how your proof types are defined.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;If you fail to add the &lt;code&gt;Ord e&lt;/code&gt; constraint to the other type constructors, you will eventually run into errors like &lt;code&gt;Can't unify &quot;So (&amp;lt;=) {{constrarg1}} x y&quot; with &quot;So (&amp;lt;=) {{constrarg}} x y&quot;&lt;/code&gt; where the compiler loses type information about the specific &lt;code&gt;Ord e&lt;/code&gt; instance when trying to pull type information through the &lt;code&gt;IsSortedZero&lt;/code&gt; or &lt;code&gt;IsSortedOne&lt;/code&gt; type constructors during type unification. That probably didn&amp;rsquo;t make much sense - especially the part about &amp;ldquo;type unification&amp;rdquo; - but you&amp;rsquo;ll probably have to debug a similar issue at some point.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2014/12/20/languages-by-hardware-distance</id>
   <title>Spectrum of Languages by Hardware&amp;nbsp;Distance</title>
   <published>2014-12-20T00:00:00+00:00</published>
   <updated>2014-12-20T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2014/12/20/languages-by-hardware-distance/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Programming languages (and the ecosystems that surround them) are incredibly interesting. They can be sliced in many different ways based on syntactic similarity, type system similarity, suitedness for various problem domains, and many other attributes.&lt;/p&gt;

&lt;p&gt;Below I present an spectrum of various languages, arranged by &lt;strong&gt;distance from the underlying hardware&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;ul class=&quot;nav nav-tabs&quot;&gt;
  &lt;li class=&quot;active&quot;&gt;
    &lt;a href=&quot;#diagram-tldr&quot; class=&quot;tab-header&quot; data-toggle=&quot;tab&quot;&gt;
      TLDR
    &lt;/a&gt;
  &lt;/li&gt;
  &lt;li class=&quot;&quot;&gt;
    &lt;a href=&quot;#diagram-full&quot; class=&quot;tab-header&quot; data-toggle=&quot;tab&quot;&gt;
      Full
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;tab-content&quot; id=&quot;spectrum-diagram&quot;&gt;
  &lt;a class=&quot;tab-pane active&quot; id=&quot;diagram-tldr&quot; href=&quot;/assets/2014/hardware-distance/tldr-125perc-72dpi.png&quot;&gt;
    &lt;img src=&quot;/assets/2014/hardware-distance/tldr-125perc-72dpi.png&quot; style=&quot;max-width: 100%;&quot; /&gt;
  &lt;/a&gt;
  &lt;a class=&quot;tab-pane&quot;        id=&quot;diagram-full&quot; href=&quot;/assets/2014/hardware-distance/full-100perc-72dpi.png&quot;&gt;
    &lt;img src=&quot;/assets/2014/hardware-distance/full-100perc-72dpi.png&quot; style=&quot;max-width: 100%;&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;A few interesting patterns become evident in this diagram:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Expressiveness &lt;span title=&quot;is proportional to&quot; style=&quot;cursor: help&quot;&gt;∝&lt;/span&gt; Distance from Hardware&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Usually the closer you are to the hardware, the more you have to think like a computer and less like a human, decreasing expressiveness.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are some outlier languages (such as Go, Lua, and Forth) which are more expressive than their distance from the hardware would suggest.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type systems tend to be similar for languages with similar hardware-distance.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Bare Metal languages like machine code and assembly have no type system at all. Every piece of data is just a machine word and no type checking is done at all.&lt;/li&gt;
&lt;li&gt;Almost Bare Metal languages like C and C++ have a type system that is just strong enough to tell the compiler how to compile operations efficiently, but these type systems are not specifically designed for the elimination of bugs or expressiveness.&lt;/li&gt;
&lt;li&gt;High Level languages care more about expressiveness, and they tend to divide into two camps: &lt;strong&gt;statically-typed&lt;/strong&gt; (Java, C#) and &lt;strong&gt;dynamically-typed&lt;/strong&gt; (Python, Ruby, Lisps).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anything that is Intermediate Typed or below has a stronger focus on the type system, usually for preventing bugs or just having very precise types.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;PhD required below this line&amp;rdquo;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I have observed generally two large groups of people that work with programming languages, the &lt;strong&gt;Practitioners&lt;/strong&gt; and the &lt;strong&gt;Academics&lt;/strong&gt;. Each group uses their own specialized jargon&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; and tends not to talk to each other that much.&lt;/li&gt;
&lt;li&gt;Languages inside the &amp;ldquo;PhD required below this line&amp;rdquo; area are generally used primarily by Academics, and therefore their documentation (often only in the form of research papers) is difficult to read by Practitioners.&lt;/li&gt;
&lt;li&gt;I currently group myself as a Practitioner who is trying to read Academic.&lt;/li&gt;
&lt;li&gt;Of course some so-called Academic languages are sometimes used in practice for commercial systems. The Java bytecode verifier, for example, is defined in Prolog.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many languages in or near this region are lumped under the vague term &lt;strong&gt;functional programming&lt;/strong&gt;, which roughly translates to a programming style that avoids mutable data structures &amp;amp; side effects by default, or just &amp;ldquo;a language that feels like Haskell&amp;rdquo; (the canonical &amp;ldquo;functional&amp;rdquo; language).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Middle of the spectrum = Sweet spot&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;There are a quite a lot of languages in the middle layers (High Level and Intermediate Typed). Probably because they intersect most with expressive languages, which are the most fun to program in.&lt;/li&gt;
&lt;li&gt;Programming near the hardware is unfun and generally unnecessary unless you&amp;rsquo;re writing an OS, an embedded system, a CPU-intensive scientific computation, or a graphics shader.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I suspect there aren&amp;rsquo;t as many languages at the bottom in Academic-land because there are fewer Academics than Practitioners, such languages are harder to write (because of more complex type systems), or because I simply am not aware of many such languages as a non-Academic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Declarative Languages that are general-purpose are rare.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Most Declarative Languages are domain-specific. Arguably Prolog is general since it answers arbitrary questions from logic. And arguably SQL is general because most data stores (and every SQL database) is queryable with it.&lt;/li&gt;
&lt;li&gt;Other examples of declarative languages not listed here are VHDL and Verilog (used for hardware design), and ReceiptTally&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; (used for personal finance).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/20/visual-guide-to-programming-language-properties/&quot;&gt;Visual Guide to Programming Language Properties&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Shows programming language features, how they are related, and which features are present in popular languages.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Visualizes some of the languages discussed in this article.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Discusses several programming languages and their unique features.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Series
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        This article is part of the &lt;a href=&quot;/articles/2013/05/11/book-outline/&quot;&gt;Programming for Perfectionists&lt;/a&gt; series.
    &lt;/p&gt;
&lt;/div&gt;



&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;When speaking of &amp;ldquo;hardware distance&amp;rdquo;, the hardware I am referring to is the common commodity hardware architectures such as x86 and ARM. It should be noted that there are also specialized architectures where Forth, Lisp, and Prolog &lt;em&gt;are&lt;/em&gt; the assembly language. And some architectures like the Burroughs actually have typed memory and pointers, which eliminates a lot of the dangers of working with untyped assembly.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Examples of Practitioner-jargon: &amp;ldquo;inheritance&amp;rdquo;, &amp;ldquo;generics&amp;rdquo;, &amp;ldquo;dependency injection&amp;rdquo;, &amp;ldquo;covariance&amp;rdquo;. Examples of Academic-jargon: &amp;ldquo;monad&amp;rdquo;, &amp;ldquo;functor&amp;rdquo;, &amp;ldquo;reduce&amp;rdquo;, &amp;ldquo;dependent type&amp;rdquo;, &amp;ldquo;currying&amp;rdquo;. More examples from this &lt;a href=&quot;http://www.slideshare.net/ScottWlaschin/fp-patterns-buildstufflt/10&quot;&gt;presentation on functional programming&lt;/a&gt;.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;ReceiptTally is a custom language of my own designed to describe household receipts. With this description it can be calculated who owes whom money for reimbursement purposes. I haven&amp;rsquo;t bothered to make this project public at this time.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2014/11/22/error-handling-styles</id>
   <title>Error handling styles in programming</title>
   <published>2014-11-22T00:00:00+00:00</published>
   <updated>2014-11-22T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2014/11/22/error-handling-styles/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;There are many ways that programs can handle errors at runtime. The excellent book &lt;a href=&quot;https://www.amazon.com/Exercises-Programming-Style-Cristina-Videira/dp/1482227371/ref=as_sl_pc_ss_til?tag=dafo07-20&amp;amp;linkCode=w01&amp;amp;linkId=7FSPMMHJB3KVNUKV&amp;amp;creativeASIN=1482227371&quot;&gt;Exercises in Programming Style&lt;/a&gt; proposes an interesting categorization of common error handling patterns. Fascinatingly, the programming language that you work in often actively encourages one particular error handling pattern over another.&lt;/p&gt;

&lt;h2&gt;Reinterpret and Continue &lt;small&gt;(Constructivist)&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;&lt;img style=&quot;float: right;&quot; src=&quot;/assets/2014/error-handling-styles/constructivist.jpg&quot; title=&quot;Constructivist&quot;/&gt;&lt;/p&gt;

&lt;p&gt;In this style, a function that receives a bad input or encounters an error always returns a sensible result to its caller, silently reinterpreting the error to a valid value. Such a function will never crash the program but may produce unexpected results in the presence of bad inputs or errors.&lt;/p&gt;

&lt;p&gt;Languages whose standard libraries and syntax regularly reinterpret errors and questionable input make it difficult to write programs that are not in this style.&lt;/p&gt;

&lt;p&gt;Environments that encourage this style:&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;float: right;&quot; src=&quot;/assets/2014/error-handling-styles/php-web.png&quot; title=&quot;PHP, HTML, CSS, JavaScript&quot;/&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PHP&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Very few PHP errors will actually crash the program - instead you get strange results and error text inserted into rendered pages.&lt;/li&gt;
&lt;li&gt;Errors are printed to a server log file that nobody reads.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTML, CSS&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Web browsers reinterpret bad markup as best they can to valid markup. Of course different browsers do this in different ways, so the only way to get a consistent rendering is to use valid markup.&lt;/li&gt;
&lt;li&gt;Rendering errors are not generally logged anywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Developers that wish to use a more Fail Fast style of error handling (see below) but are forced to write in one of these languages may use special validation and linting tools to look for errors in the program text before they can be reinterpreted.&lt;/p&gt;

&lt;h2&gt;Fail Fast &lt;small&gt;(Tantrum, Passive Aggressive)&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;In this style, a function that receives a bad input or encounters an error refuses to continue, returning an error back to its caller.&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;float: right;&quot; src=&quot;/assets/2014/error-handling-styles/tantrum.jpg&quot; title=&quot;Tantrum&quot;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;float: right; clear: both; margin-top: .5em; margin-left: .5em;&quot; src=&quot;/assets/2014/error-handling-styles/passive-aggressive.jpg&quot; title=&quot;Passive Aggressive&quot;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Exercises-Programming-Style-Cristina-Videira/dp/1482227371/ref=as_sl_pc_ss_til?tag=dafo07-20&amp;amp;linkCode=w01&amp;amp;linkId=7FSPMMHJB3KVNUKV&amp;amp;creativeASIN=1482227371&quot;&gt;Exercises in Programming Style&lt;/a&gt; makes the additional distinction that functions in some programs try to handle errors immediately at their point of detection no matter what (&amp;ldquo;Tantrum&amp;rdquo;), whereas functions in other programs prefer to bubble up errors to callers until a caller with enough context is reached that decides to actually handle the error (&amp;ldquo;Passive Aggressive&amp;rdquo;).&lt;/p&gt;

&lt;p&gt;Programs in the Tantrum substyle have lots of error handling code scattered throughout the program text, whereas programs in the Passive Aggressive substyle tend to consolidate most error handling code in top-level functions and let lower-level code just bubble up errors.&lt;/p&gt;

&lt;p&gt;Languages that have built-in exceptions make it easy to implement programs in the Passive Aggressive substyle.&lt;/p&gt;

&lt;p&gt;Environments that encourage this style:&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;float: right;&quot; src=&quot;/assets/2014/error-handling-styles/java-csharp-python.png&quot; title=&quot;Java, C#, Python&quot;/&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/07/13/error-handling/&quot;&gt;Error Handling&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;More comprehensively discusses considerations and specific implementation techniques for writing code that is robust in the presence of errors.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2016/05/17/abandonment-vs-unchecked-exceptions-for-error-handling/&quot;&gt;Abandonment vs. Unchecked Exceptions for Error Handling&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes abandonment, an uncommon error-handling style.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2014/06/24/submitting-a-python-app-to-the-mac-app-store</id>
   <title>Submitting a Python App to the Mac App Store</title>
   <published>2014-06-24T00:00:00+00:00</published>
   <updated>2014-06-24T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2014/06/24/submitting-a-python-app-to-the-mac-app-store/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Recently I needed to submit a Python app to the Mac App Store. Since there seemed to be no good documentation online for doing this, I had to figure it out myself. Here&amp;rsquo;s what I learned:&lt;/p&gt;

&lt;h2&gt;Building a Python app for the Mac App Store&lt;/h2&gt;

&lt;p&gt;Below I will explain how to make a Python script into a Mac App Store app. I would recommend that you download my &lt;a href=&quot;https://github.com/davidfstr/Python-in-Mac-App-Store#hello-app-store&quot;&gt;example Python app that can be submitted to the Mac App Store&lt;/a&gt; and examine its build system while reading the rest of this article.&lt;/p&gt;

&lt;h3&gt;Get a Python script&lt;/h3&gt;

&lt;p&gt;First, I assume you already have a Python script that you&amp;rsquo;d like to package as an application and submit.&lt;/p&gt;

&lt;p&gt;My example app uses &lt;code&gt;src/HelloAppStore.py&lt;/code&gt; as the main script.&lt;/p&gt;

&lt;h3&gt;Make it into a regular app&lt;/h3&gt;

&lt;p&gt;A Python script, along with its included Python modules and dependencies, can be bundled into a regular Mac app using &lt;a href=&quot;http://svn.pythonmac.org/py2app/py2app/trunk/doc/index.html#abstract&quot;&gt;py2app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I won&amp;rsquo;t repeat the py2app documentation, but you generally need to create a &lt;code&gt;setup.py&lt;/code&gt; file that looks something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from setuptools import setup

APP = ['src/HelloAppStore.py']
DATA_FILES = []
OPTIONS = {
    'argv_emulation': True,
    #'iconfile': 'src/Icon.icns',  # optional
    #'plist': 'src/Info.plist',    # optional
}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then you can build &lt;code&gt;dist/HelloAppStore.app&lt;/code&gt; into a nice double-clickable app by running the command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;python setup.py py2app
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;My example app runs the above command as part of the &lt;code&gt;./build-app.sh&lt;/code&gt; script.&lt;/p&gt;

&lt;h3&gt;Alter the app to conform to Mac App Store constraints&lt;/h3&gt;

&lt;p&gt;There are several additional nontrivial restrictions that must be satisfied before an app can be submitted to the Mac App Store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It must be able to run in &lt;strong&gt;sandboxed&lt;/strong&gt; mode.&lt;/li&gt;
&lt;li&gt;It must be &lt;strong&gt;code-signed&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It must not depend on any &lt;strong&gt;deprecated APIs&lt;/strong&gt; (like QuickTime), even from included libraries.&lt;/li&gt;
&lt;li&gt;It must not include any &lt;strong&gt;PowerPC code&lt;/strong&gt;, even from included libraries.&lt;/li&gt;
&lt;li&gt;It must have a &lt;strong&gt;large app icon&lt;/strong&gt; (with sizes up to 1024x1024).&lt;/li&gt;
&lt;li&gt;It must have a specified &lt;strong&gt;app store category&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It must not have any content that Apple finds &lt;strong&gt;offensive&lt;/strong&gt; in its sole discretion.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;An exhaustive list of restrictions can be found in the &lt;a href=&quot;https://developer.apple.com/appstore/mac/resources/approval/guidelines.html&quot;&gt;Mac App Store Review Guidelines&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Sandboxing&lt;/h4&gt;

&lt;p&gt;Mac App Store apps must be sandboxed. Sandboxed apps are restricted in several ways, but the most significant restriction is the &lt;strong&gt;inability to read/write arbitrary files&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In particular an app cannot write to a file outside of its sandbox container unless a &lt;strong&gt;native&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; open/save dialog is used to prompt for the location of the file or the file already resides within the app&amp;rsquo;s container directory.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a good idea to read the &lt;a href=&quot;https://developer.apple.com/app-sandboxing/&quot;&gt;App Sandboxing&lt;/a&gt; documentation to understand the full set of restrictions and how to overcome them when necessary (and when possible).&lt;/p&gt;

&lt;p&gt;My example app enables sandboxing by specifying that &lt;code&gt;com.apple.security.app-sandbox = true&lt;/code&gt; in the &lt;code&gt;src/app.entitlements&lt;/code&gt; file. This entitlements file is used in the code-signing process described in the next section.&lt;/p&gt;

&lt;h4&gt;Code-signing&lt;/h4&gt;

&lt;p&gt;Mac App Store apps must be code-signed. This means you must go through some extra hoops to generate signing certificates, download them to your dev machine, and alter your build script to sign the final app package with it.&lt;/p&gt;

&lt;p&gt;These certificates have to be generated by Apple as part of your Mac Developer Program subscription ($99/year). And renewed annually if you wish to continue making app updates.&lt;/p&gt;

&lt;p&gt;Since Python apps are built outside of Xcode, you&amp;rsquo;ll have to use the &lt;code&gt;codesign&lt;/code&gt; tool manually to sign your app.&lt;/p&gt;

&lt;p&gt;My example app runs the &lt;code&gt;codesign&lt;/code&gt; tool as part of the &lt;code&gt;./build-app.sh&lt;/code&gt; script, recursively signing the inner frameworks, helper tools, and finally the outer application binaries. As part of the signing process the application binaries are also embedded with &lt;em&gt;entitlements&lt;/em&gt;, which are used to enable sandboxing.&lt;/p&gt;

&lt;p&gt;See the &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Security/Conceptual/CodeSigningGuide/CodeSigningGuide.pdf&quot;&gt;Code Signing Guide&lt;/a&gt; for more information about manual code-signing.&lt;/p&gt;

&lt;h4&gt;Deprecated APIs&lt;/h4&gt;

&lt;p&gt;Your Python script probably won&amp;rsquo;t be directly using any deprecated APIs. However your Python script might depend on other libraries that &lt;em&gt;do&lt;/em&gt;. Such dependencies can be difficult or impossible to eliminate. Typically you have to modify and recompile the dependency manually.&lt;/p&gt;

&lt;p&gt;In particular the very popular &lt;strong&gt;wxPython&lt;/strong&gt; GUI toolkit &lt;a href=&quot;https://groups.google.com/forum/#!topic/wxpython-mac/BeUS9GHigvE&quot;&gt;depends on deprecated QuickTime APIs&lt;/a&gt; at the time of writing, making any Python app that depends on it inadmissible to be submitted to the Mac App Store.&lt;/p&gt;

&lt;p&gt;My example app has no workarounds for deprecated APIs.&lt;/p&gt;

&lt;h4&gt;PowerPC Code&lt;/h4&gt;

&lt;p&gt;Your Python script probably won&amp;rsquo;t be directly using any old PowerPC code. However, again, your Python script might depend on other libraries that &lt;em&gt;do&lt;/em&gt;. In fact Python 2.7 itself includes PowerPC code.&lt;/p&gt;

&lt;p&gt;Luckily any PowerPC code can be stripped out easily using the &lt;code&gt;lipo&lt;/code&gt; tool, so you just need to add some extra &lt;code&gt;lipo&lt;/code&gt; commands to your build script.&lt;/p&gt;

&lt;p&gt;My example app uses &lt;code&gt;lipo&lt;/code&gt; in the &lt;code&gt;./build-app.sh&lt;/code&gt; script to remove PowerPC code from the &lt;code&gt;python2.7&lt;/code&gt; library.&lt;/p&gt;

&lt;h4&gt;Large App Icon&lt;/h4&gt;

&lt;p&gt;If you don&amp;rsquo;t have an app icon you&amp;rsquo;ll have to create one. If you &lt;em&gt;do&lt;/em&gt; already have an app icon, I&amp;rsquo;ll bet you it doesn&amp;rsquo;t meet the minimum 1024x1024 pixel size requirement.&lt;/p&gt;

&lt;p&gt;Creating an icon entails creating several images for your icon at various specific sizes, and then using the &lt;code&gt;iconutil&lt;/code&gt; command to generate a final &lt;code&gt;.icns&lt;/code&gt; icon file.&lt;/p&gt;

&lt;p&gt;My example app contains a &lt;code&gt;./build-icon.sh&lt;/code&gt; script that can be used to generate &lt;code&gt;src/Icon.icns&lt;/code&gt; from images in the &lt;code&gt;src/Icon.iconset&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;See the &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/AppleHIGuidelines/IconsImages/IconsImages.html#//apple_ref/doc/uid/20000967-TP6&quot;&gt;Icon Design Guidelines&lt;/a&gt; in the OS X Human Interface Guidelines for more information about creating icons.&lt;/p&gt;

&lt;h4&gt;App Store Category&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;Info.plist&lt;/code&gt; file inside a Mac App Store app is required to specify what category on the Mac App Store it belongs to under the &lt;code&gt;LSApplicationCategoryType&lt;/code&gt; key.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;
&amp;lt;plist version=&quot;1.0&quot;&amp;gt;
&amp;lt;dict&amp;gt;
    ...
    &amp;lt;key&amp;gt;LSApplicationCategoryType&amp;lt;/key&amp;gt;
    &amp;lt;string&amp;gt;public.app-category.reference&amp;lt;/string&amp;gt;
    ...
&amp;lt;/dict&amp;gt;
&amp;lt;/plist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far as I can tell, the set of valid values for this key is not documented anywhere. Therefore to find new values, I created a new Cocoa Application project in Xcode (where I could specify the app category in a dropdown), compiled the app, and opened its &lt;code&gt;Info.plist&lt;/code&gt; file to see what value it had for the &lt;code&gt;LSApplicationCategoryType&lt;/code&gt; key.&lt;/p&gt;

&lt;h2&gt;Submitting your app to the store&lt;/h2&gt;

&lt;p&gt;Regular apps written in Objective-C for the Mac App Store are usually submitted directly from within Xcode. This is not an option for Python apps that you build outside of Xcode.&lt;/p&gt;

&lt;p&gt;Instead you have to use an older app submission tool called &lt;strong&gt;Application Loader&lt;/strong&gt; to upload your app. However Application Loader doesn&amp;rsquo;t submit a &lt;code&gt;.app&lt;/code&gt; package directly; it requires an installer &lt;code&gt;.pkg&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;An installer package can be built from your &lt;code&gt;.app&lt;/code&gt; using the &lt;code&gt;productbuild&lt;/code&gt; tool.&lt;/p&gt;

&lt;p&gt;My example app runs the &lt;code&gt;productbuild&lt;/code&gt; tool as part of the &lt;code&gt;./build-pkg.sh&lt;/code&gt; script which creates an installer package containing the app.&lt;/p&gt;

&lt;p&gt;For more information about the &lt;code&gt;productbuild&lt;/code&gt; tool, see its man page.&lt;/p&gt;

&lt;h2&gt;Fin&lt;/h2&gt;

&lt;p&gt;Hopefully you should now have a good idea of what is involved in submitting a Python app to the Mac App Store.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;d like to actually try out the process of submitting an app, try building and submitting my &lt;a href=&quot;https://github.com/davidfstr/Python-in-Mac-App-Store#hello-app-store&quot;&gt;example app&lt;/a&gt; using the instructions in its README.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Please send comments and corrections to &lt;a href=&quot;/contact/&quot;&gt;David Foster&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Therefore if you are using a GUI toolkit that uses a simulated open/save dialog rather than a native one, your app won&amp;rsquo;t be able to access the files the user selects!&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2014/02/17/agda-second-impressions</id>
   <title>Agda: Second Impressions</title>
   <published>2014-02-17T00:00:00+00:00</published>
   <updated>2014-02-17T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2014/02/17/agda-second-impressions/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;These are my second impressions of the Agda programming language after writing (or trying to write) a few simple Agda programs.&lt;/p&gt;

&lt;p&gt;If you only want the highlights, just read the &lt;a href=&quot;#executive-summary&quot;&gt;Executive Summary&lt;/a&gt;. If you also want to see supporting material and notes, continue reading further.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#executive-summary&quot;&gt;Executive Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#programs&quot;&gt;Programs&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#peano&quot;&gt;Peano&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#hellonumber&quot;&gt;HelloNumber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#helloworld&quot;&gt;HelloWorld&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#printtwothings&quot;&gt;PrintTwoThings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#echoinput&quot;&gt;EchoInput&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#promptforname&quot;&gt;PromptForName&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#echoinputreverse&quot;&gt;EchoInputReverse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#parseint&quot;&gt;ParseInt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;executive-summary&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Executive Summary&lt;/h2&gt;

&lt;p&gt;Agda is simultaneously touted as (1) a dependently-typed &lt;em&gt;programming language&lt;/em&gt; and (2) a proof assistant. I find that Agda is a considerably better proof assistant than it is a programming language at this time.&lt;/p&gt;

&lt;p&gt;A few issues I found when trying to use Agda as a programming language to get real work done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I/O is painful:

&lt;ul&gt;
&lt;li&gt;The Agda standard library lacks any functions for reading from standard input. Clearly the ability to write basic command-line programs is not a priority for the Agda library implementors.

&lt;ul&gt;
&lt;li&gt;You must implement such functions yourself as native functions that call into Haskell.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The I/O that does exist is based on Haskell&amp;rsquo;s I/O monad, which by itself is difficult enough to learn.&lt;/li&gt;
&lt;li&gt;It appears that one has to learn what &lt;a href=&quot;http://adam.chlipala.net/cpdt/html/Coinductive.html&quot;&gt;coinduction&lt;/a&gt; is in order to use Agda&amp;rsquo;s native &lt;code&gt;IO&lt;/code&gt; module. Yet another abstract academic construct.

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I can work around this by restricting myself to the &lt;code&gt;IO.Primitive&lt;/code&gt; module. This module directly mirrors Haskell&amp;rsquo;s IO system and thus only requires knowledge of monads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some basic numerical operations are very inefficient.

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;div&lt;/code&gt; and &lt;code&gt;mod&lt;/code&gt; operators for the default implementation of natural numbers (&lt;code&gt;Data.Nat&lt;/code&gt;) run in &lt;em&gt;linear&lt;/em&gt; time relative to the magnitude of the divisor.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;

&lt;ul&gt;
&lt;li&gt;Consequently it takes about &lt;strong&gt;16 seconds&lt;/strong&gt; to print the number 4000 because of division inefficiency when formatting the number for display.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At least &lt;code&gt;≤?&lt;/code&gt;, &lt;code&gt;≟&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, and &lt;code&gt;*&lt;/code&gt; appear to be logarithmic- or constant-time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &amp;ldquo;Hello World&amp;rdquo; program compiles to a 14 MB binary. Unacceptably large.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &amp;ldquo;Hello World&amp;rdquo; program takes 3 seconds to compile. Unacceptably slow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;It takes quite a lot of effort to get a basic environment running. You have to:

&lt;ul&gt;
&lt;li&gt;Install Agda.&lt;/li&gt;
&lt;li&gt;Install the Agda standard library separately.&lt;/li&gt;
&lt;li&gt;Compile the Agda IO.FFI module manually.&lt;/li&gt;
&lt;li&gt;Install and learn Emacs.&lt;/li&gt;
&lt;li&gt;Configure Emacs to work with Agda.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/01/24/agda-notes-and-evaluation/&quot;&gt;Agda: First Impressions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Previous article in this series.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;programs&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Programs&lt;/h2&gt;

&lt;p&gt;The following are all the simple programs I&amp;rsquo;ve written with Agda so far.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;peano&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Peano&lt;/h3&gt;

&lt;p&gt;A manual reimplementation of natural numbers (i.e. non-negative integers) just so that I can get my Agda environment up and running.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;Peano.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module Peano where

data ℕ : Set where
  zero : ℕ
  suc : ℕ → ℕ

_+_ : ℕ → ℕ → ℕ
zero + zero  = zero
zero + n     = n
(suc n) + n' = suc (n + n')
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;I resent being forced to use Emacs as opposed to my favorite text editor.

&lt;ul&gt;
&lt;li&gt;Particularly since the installation instructions are not bulletproof.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;hellonumber&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;HelloNumber&lt;/h3&gt;

&lt;p&gt;A program that prints the number 5.&lt;/p&gt;

&lt;p&gt;No more reimplementing silly stuff like numbers. Let&amp;rsquo;s use the standard library.&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;HelloNumber.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module HelloNumber where

-- Agda standard library 0.7
open import Data.Nat
open import Data.Nat.Show using (show)
open import Data.Unit using (⊤)
open import IO
import IO.Primitive as Prim

five : ℕ
five = 5

main' : IO ⊤
main' = putStrLn (show five)

main : Prim.IO ⊤
main = run main'
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/agda/agda-stdlib/&quot;&gt;Agda standard library&lt;/a&gt; is not installed with Agda by default. WTF?

&lt;ul&gt;
&lt;li&gt;It also has not yet reached v1.0.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Standard library IO appears to be defined equivalently to Haskell&amp;rsquo;s IO monad.&lt;/li&gt;
&lt;li&gt;I am amused that compiling the IO module also implies compiling the entirety of Algebra.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m sad that declaration order in Agda matters. In particular items must be declared before they can be used.

&lt;ul&gt;
&lt;li&gt;This forces me to write programs in the annoying bottom-to-top order, requiring lots of extra up-down eye scanning for large programs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Surprise! The main function doesn&amp;rsquo;t have type &lt;code&gt;IO ⊤&lt;/code&gt; (which would be equivalent to the Haskell &lt;code&gt;IO ()&lt;/code&gt;). Instead it has type &lt;code&gt;Prim.IO ⊤&lt;/code&gt; which can be obtained by passing an &lt;code&gt;IO ⊤&lt;/code&gt; through the &lt;code&gt;IO.run&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Even after installing the standard library, I have to manually compile the IO.FFI library to perform basic IO. *grumble*&lt;/li&gt;
&lt;li&gt;My test program that just prints the number 5 takes up 14 MB. What a waste of space&amp;hellip;

&lt;ul&gt;
&lt;li&gt;I assume those 14 MB are primarily the bulk added by the standard library.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;helloworld&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;HelloWorld&lt;/h3&gt;

&lt;p&gt;Now let&amp;rsquo;s try printing strings, which should allow writing the standard &amp;ldquo;Hello world&amp;rdquo; program.&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;HelloWorld.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module HelloWorld where

-- Agda standard library 0.7
open import Data.String
open import Data.Unit using (⊤)
open import IO
import IO.Primitive as Prim

greeting : String
greeting = &quot;Hello World&quot;

main' : IO ⊤
main' = putStrLn greeting

main : Prim.IO ⊤
main = run main'
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;It takes 3 seconds to type-check my Hello World program when compiling to an executable. That&amp;rsquo;s really slow.

&lt;ul&gt;
&lt;li&gt;I hope those 3 seconds are just fixed overhead and not proportional to the size of the program.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;printtwothings&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;PrintTwoThings&lt;/h3&gt;

&lt;p&gt;Now let&amp;rsquo;s try stringing multiple IO actions together.&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;PrintTwoThings.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module PrintTwoThings where

-- Agda standard library 0.7
open import Coinduction using (♯_)
open import Data.String
open import Data.Unit using (⊤)
open import IO
import IO.Primitive as Prim

doThis : IO ⊤
doThis = putStr &quot;Everybody say coinductive deep embedding! &quot;

thenThat : IO ⊤
thenThat = putStrLn &quot;Coinductive deep embedding!&quot;

main' : IO ⊤
main' = (♯ doThis) &amp;gt;&amp;gt; (♯ thenThat)

main : Prim.IO ⊤
main = run main'
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Surprise! The &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; operator used to join two IO actions isn&amp;rsquo;t &lt;code&gt;IO A -&amp;gt; IO B -&amp;gt; IO B&lt;/code&gt;. Rather it is &lt;code&gt;∞ (IO A) -&amp;gt; ∞ (IO B) -&amp;gt; IO B&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;This means I need to wrap IO actions inside the &lt;code&gt;∞&lt;/code&gt; type before I can chain them together.&lt;/li&gt;
&lt;li&gt;What is the &lt;code&gt;∞&lt;/code&gt; type? No idea. It has something to do with &amp;ldquo;coinduction&amp;rdquo;, which Wikipedia failed to explain to me coherently.

&lt;ul&gt;
&lt;li&gt;Information &lt;a href=&quot;http://people.inf.elte.hu/divip/AgdaTutorial/Revise.Coinduction.html&quot;&gt;here&lt;/a&gt; suggests that a &lt;code&gt;∞ A&lt;/code&gt; represents a lazy unevaluated computation of type &lt;code&gt;A&lt;/code&gt; that might not terminate when it is actually evaluated.&lt;/li&gt;
&lt;li&gt;Representing the possibility of nontermination explicitly is probably required since Agda normally requires all of its function definitions to provably terminate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;According to the &lt;code&gt;Coinduction&lt;/code&gt; library, I can make a &lt;code&gt;∞&lt;/code&gt; using the &lt;code&gt;♯&lt;/code&gt; operator which takes a value of any type &lt;code&gt;A&lt;/code&gt; and makes a &lt;code&gt;∞ A&lt;/code&gt; out of it.&lt;/li&gt;
&lt;li&gt;Therefore instead of &lt;code&gt;action1 &amp;gt;&amp;gt; action2&lt;/code&gt; I need &lt;code&gt;♯ action1 &amp;gt;&amp;gt; ♯ action2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;!--
#### Interlude: Agda evaluates strictly?

It appears that Agda performs strict evaluation by default. Thus the introducion of the &quot;coinductive&quot; type `∞` to represent potentially infinite computations.

However if this is the case then calling out to Haskell functions through the foreign function interface could get weird since Haskell *is* a lazily evaluation language.
--&gt;


&lt;p&gt;&lt;a id=&quot;echoinput&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;EchoInput&lt;/h3&gt;

&lt;p&gt;Read a line from standard input. Write it back to the screen.&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;EchoInput.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module EchoInput where

-- Agda standard library 0.7
open import Data.String
open import Foreign.Haskell using (Unit)
open import IO.Primitive

postulate
  getLine : IO Costring

{-# COMPILED getLine getLine #-}

doThis : IO Costring
doThis = getLine

thenThat : Costring → IO Unit
thenThat = λ s → putStrLn s

main : IO Unit
main = doThis &amp;gt;&amp;gt;= thenThat
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;There is no function in the standard library to read from standard input. Nor is there a reference to &lt;code&gt;stdin&lt;/code&gt; itself. Unbelievable.

&lt;ul&gt;
&lt;li&gt;I can &lt;a href=&quot;http://people.inf.elte.hu/divip/AgdaTutorial/Revise.IO.html&quot;&gt;define getLine manually&lt;/a&gt; using the foreign function interface. But I really shouldn&amp;rsquo;t have to define such a simple function. This should be in the standard library&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When writing native IO functions it&amp;rsquo;s a lot easier to directly use Agda&amp;rsquo;s &lt;code&gt;Primitive.IO&lt;/code&gt; module instead of the regular &lt;code&gt;IO&lt;/code&gt; module. I no longer need to use &lt;code&gt;∞&lt;/code&gt; or &lt;code&gt;♯&lt;/code&gt; either, which is nice.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;promptforname&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;PromptForName&lt;/h3&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;PromptForName.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module PromptForName where

-- Agda standard library 0.7
open import Data.String
open import Foreign.Haskell using (Unit)
open import IO.Primitive

postulate
  getLine : IO Costring

{-# COMPILED getLine getLine #-}

main : IO Unit
main = 
  putStrLn (toCostring &quot;What's your name?&quot;) &amp;gt;&amp;gt;= (λ _ → 
  getLine &amp;gt;&amp;gt;= (λ s → 
  putStr (toCostring &quot;Hello &quot;) &amp;gt;&amp;gt;= (λ _ → 
  putStrLn s)))
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Surprise! &lt;code&gt;Primitive.IO&lt;/code&gt; defines the &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; operator but not &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;. Asymmetric with the regular &lt;code&gt;IO&lt;/code&gt; module.&lt;/li&gt;
&lt;li&gt;Native IO functions require &lt;code&gt;Costring&lt;/code&gt; objects. So a string literal has to be passed to &lt;code&gt;toCostring&lt;/code&gt; to be used.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;echoinputreverse&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;EchoInputReverse&lt;/h3&gt;

&lt;p&gt;Read a line from standard input. Reverse it in Agda. Write the reversed line back to the screen.&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;EchoInputReverse.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module EchoInputReverse where

-- Agda standard library 0.7
open import Data.List using (reverse)
open import Data.String
open import Foreign.Haskell using (Unit)
open import IO.Primitive

postulate
  getLine : IO String

{-# COMPILED getLine getLine #-}

main : IO Unit
main = 
  getLine &amp;gt;&amp;gt;= (λ s → 
  return (toCostring (fromList (reverse (toList s)))) &amp;gt;&amp;gt;= (λ s' → 
  putStrLn s'))
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Problem: The line from standard input is a &lt;code&gt;Costring&lt;/code&gt;. I can&amp;rsquo;t reverse it or do anything useful with it without first converting it to a &lt;code&gt;String&lt;/code&gt;. But there is no function in the standard library to do this conversion, even as a runtime cast.&lt;/li&gt;
&lt;li&gt;Surprise workaround: Even though the Haskell type &lt;code&gt;String&lt;/code&gt; maps to the Agda type &lt;code&gt;Costring&lt;/code&gt; in the general case, it is still possible to postulate that it maps directly to the Agda type &lt;code&gt;String&lt;/code&gt; for certain functions where you can assert that the string won&amp;rsquo;t be infinite.

&lt;ul&gt;
&lt;li&gt;So the Agda FFI must be capable of performing implicit coercion between the native &lt;code&gt;Costring&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; datatypes. This is &lt;a href=&quot;http://wiki.portal.chalmers.se/agda/agda.php?n=Docs.FFI&quot;&gt;not documented&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;This approach has the disadvantage that it marks the result of &lt;code&gt;getLine&lt;/code&gt; as being a &lt;em&gt;finite&lt;/em&gt; string when it may not in fact be. See discussion at &lt;a href=&quot;http://stackoverflow.com/questions/21808186/reading-a-line-of-standard-input-as-a-string-instead-of-a-costring/&quot;&gt;StackOverflow&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;parseint&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;ParseInt&lt;/h3&gt;

&lt;p&gt;Prompt the user for a number, parse it, and output it. If an invalid number was input, output zero.&lt;/p&gt;

&lt;div class=&quot;accordion&quot;&gt;
  &lt;div class=&quot;accordion-group&quot;&gt;
    &lt;div class=&quot;accordion-heading&quot;&gt;
      &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; href=&quot;#&quot;&gt;
        &lt;span class=&quot;expand-symbol&quot;&gt;&lt;/span&gt;
    &lt;code&gt;ParseInt.agda&lt;/code&gt;
      &lt;/a&gt;
    &lt;/div&gt;
    &lt;div class=&quot;accordion-body collapse&quot;&gt;
      &lt;div class=&quot;accordion-inner&quot;&gt;
    &lt;pre&gt;&lt;code&gt;module ParseInt where

-- Agda standard library 0.7
open import Data.Char
open import Data.List
open import Data.Maybe
open import Data.Nat
open import Data.Nat.Show
open import Data.String
open import Foreign.Haskell using (Unit)
open import IO.Primitive

postulate
  getLine : IO String

{-# COMPILED getLine getLine #-}

parseInt : String → Maybe ℕ
parseInt s = 
  then? (unwrap (parseDigits s)) (λ s' → 
  just (digitsToℕ s'))
  where
    parseDigits : String → List (Maybe ℕ)
    parseDigits s = map toDigit (toList s) where
      toDigit : Char → Maybe ℕ
      toDigit '0' = just 0
      toDigit '1' = just 1
      toDigit '2' = just 2
      toDigit '3' = just 3
      toDigit '4' = just 4
      toDigit '5' = just 5
      toDigit '6' = just 6
      toDigit '7' = just 7
      toDigit '8' = just 8
      toDigit '9' = just 9
      toDigit _   = nothing

    -- TODO: There's probably a standard-library function that does this
    --       but I can't find it.
    unwrap : List (Maybe ℕ) → Maybe (List ℕ)
    unwrap xs = unwrap' (just []) xs where
      unwrap' : Maybe (List ℕ) → List (Maybe ℕ) → Maybe (List ℕ)
      unwrap' (just xs) (just y ∷ ys) = unwrap' (just (Data.List._++_ xs [ y ])) ys  -- makes unwrap O(N^2)!
      unwrap' (just xs) (nothing ∷ _) = nothing
      unwrap' (just xs) []            = just xs
      unwrap' nothing   _             = nothing

    -- TODO: Look for a monadic _&amp;gt;&amp;gt;=_ that does the same thing
    then? : {A : Set} → {B : Set} → Maybe A → (A → Maybe B) → Maybe B
    then? nothing _ = nothing
    then? (just r1) op2 = op2 r1

    digitsToℕ : List ℕ → ℕ
    digitsToℕ xs = digitsToℕ' (reverse xs) where
      digitsToℕ' : List ℕ → ℕ
      digitsToℕ' []       = 0
      digitsToℕ' (x ∷ xs) = x + (10 * (digitsToℕ' xs))

ℕ? : Maybe ℕ -&amp;gt; ℕ
ℕ? (just x) = x
ℕ? nothing  = 0

main : IO Unit
main = 
  getLine &amp;gt;&amp;gt;= (λ s → 
  return (show (ℕ? (parseInt s))) &amp;gt;&amp;gt;= (λ s' → 
  putStrLn (toCostring s')))
&lt;/code&gt;&lt;/pre&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Agda type checking errors are really hard to read:

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Actual:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;List Char !=&amp;lt; _A_10 s → _B_11 s of type Set
when checking that the expression toList s has type
_A_10 s → _B_11 s
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Expected type (A → B) but found type (List Char).
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Agda&amp;rsquo;s &lt;code&gt;show&lt;/code&gt; function that converts a natural number to a string has quadratic performance!

&lt;ul&gt;
&lt;li&gt;It takes 0.3s to print 1000, 2.2s to print 2000, 6.9s to print 3000, and 15.9s to print 4000.&lt;/li&gt;
&lt;li&gt;This is crazy! It probably means that at least one of {&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;mod&lt;/code&gt;} is not constant time. Not cool.

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Indeed the &lt;code&gt;_divMod_&lt;/code&gt; operator runs in &lt;em&gt;linear&lt;/em&gt; time with respect to the magnitude of the dividend. Madness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Surprise! Equality comparison between two numbers is not &lt;code&gt;=&lt;/code&gt; or &lt;code&gt;==&lt;/code&gt; but rather &lt;code&gt;≟&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;It doesn&amp;rsquo;t return a &lt;code&gt;Bool&lt;/code&gt; either. Instead it returns a fancy boolean called a &lt;code&gt;Decidable&lt;/code&gt; with an embedded equality proof.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Decidable&lt;/code&gt; can be converted to a regular boolean with the &lt;code&gt;⌊_⌋&lt;/code&gt; operator. Weird.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I suspect that (arbitrary precision) natural numbers from &lt;code&gt;Data.Nat&lt;/code&gt; take &lt;em&gt;linear&lt;/em&gt; memory to represent rather than &lt;em&gt;logarithmic&lt;/em&gt;.

&lt;ul&gt;
&lt;li&gt;There is &lt;code&gt;Data.Bin&lt;/code&gt; which represents natural numbers using binary, but most of the standard library doesn&amp;rsquo;t use it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;There is another module called &lt;code&gt;Data.Bin&lt;/code&gt; which provides a representation of natural numbers which uses an efficient binary representation. But most of the standard library does not use it.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;I found configuring Emacs for Agda to be nontrivial. I had to learn enough Emacs Lisp to debug my &lt;code&gt;.emacs&lt;/code&gt; configuration file.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Kudos to &lt;a href=&quot;https://github.com/liamoc/learn-you-an-agda/blob/master/pages/peano.md&quot;&gt;Learn You an Agda &gt; Hello, Peano&lt;/a&gt; for helping me implement this first Agda program.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2014/01/24/agda-notes-and-evaluation</id>
   <title>Agda: First Impressions</title>
   <published>2014-01-24T00:00:00+00:00</published>
   <updated>2014-01-24T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2014/01/24/agda-notes-and-evaluation/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;These are my first impressions of the Agda programming language after researching it in some depth but before writing any actual Agda programs.&lt;/p&gt;

&lt;p&gt;If you only want the highlights, just read the &lt;a href=&quot;#executive-summary&quot;&gt;Executive Summary&lt;/a&gt;. If you also want to see supporting material and notes, continue reading further.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#executive-summary&quot;&gt;Executive Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#environment&quot;&gt;Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#libraries&quot;&gt;Libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#papers&quot;&gt;Papers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#books&quot;&gt;Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#other-resources&quot;&gt;Other Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;executive-summary&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Executive Summary&lt;/h2&gt;

&lt;p&gt;Agda, by virtue of it possessing a &lt;em&gt;dependent type system&lt;/em&gt;, makes it a very powerful programming language. Agda is distinguished from its cousins like Coq in that it makes more of an effort at being a &lt;em&gt;programming language&lt;/em&gt; as opposed to being merely a proof assistant. Certainly worthy of study for the purpose of learning what a truly powerful type system is capable of expressing.&lt;/p&gt;

&lt;p&gt;However Agda I judge to not presently be worthy as a full production-quality programming language, suitable for long term development. My reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agda lacks a package manager

&lt;ul&gt;
&lt;li&gt;Acts as a barrier for the creation of 3rd party libraries.
A language cannot be used effectively without 3rd party libraries.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Library discoverability is also impaired.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The standard library has a version number less than 1.0, namely 0.7.

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A lack of a forward-compatibility promise from the standard library
is not acceptable for long term development.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I can find no books about Agda development, let alone &lt;em&gt;real-world&lt;/em&gt;
Agda development.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Other tripping points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agda does not have a (traditional-style) documentation generator tool,
which discourages somewhat the creation of API documentation and
especially the creation of guide-level documentation.

&lt;ul&gt;
&lt;li&gt;Agda API documentation is instead issued via hyperlinked versions
of Agda source code, which appear to emulate the Agda Emacs mode
that Agda is traditionally developed with.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Such API documentation &lt;em&gt;can&lt;/em&gt; be used effectively but it is not the
format that the larger programming community expects (i.e. styled
HTML) and is lacking in aesthetic appeal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agda only appears to have integration with the Emacs code editor.
In particular there is no obvious integration with any GUI code editors,
like Sublime Text. And such editor integration is &lt;em&gt;necessary&lt;/em&gt; at minimum
for the Unicode-style input that Agda requires.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Agda&amp;rsquo;s main website and &amp;ldquo;marketing&amp;rdquo; has very little polish.

&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s a shame that this matters, but it makes Agda appear unfinished
and not ready for prime time. In practice this will scare away users.&lt;/li&gt;
&lt;li&gt;The main website, for example, is just a stock wiki.&lt;/li&gt;
&lt;li&gt;Agda has no logo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I expect that many of these shortcomings will be addressed over time.&lt;/p&gt;

&lt;p&gt;In the meantime, as I mentioned before, I think Agda is still worthy of investigation for expanding one&amp;rsquo;s knowledge of what is possible in a powerful type system. In fact, any language where you can do something like write a sorting function that both works and proves itself to be a correct implementation in the same stroke deserves a closer look.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/02/17/agda-second-impressions/&quot;&gt;Agda: Second Impressions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Next article in this series.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;getting-started&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;Official website of Agda is &lt;a href=&quot;http://wiki.portal.chalmers.se/agda/pmwiki.php&quot;&gt;http://wiki.portal.chalmers.se/agda/pmwiki.php&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Yes, it&amp;rsquo;s a wiki. Automatically lowers the quality. :-(&lt;/li&gt;
&lt;li&gt;(1) &amp;ldquo;Agda is a dependently typed functional programming language.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;(2) &amp;ldquo;Agda is a proof assistant.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Uses Unicode operators all over the place. Nice to read. Tricky to type. Even library developers use them.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;environment&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Environment&lt;/h2&gt;

&lt;p&gt;Has 3 backends: Haskell, JavaScript, and Epic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only the Haskell one should be taken seriously, since the
latest version of the standard library (0.7) only supports
the Haskell backend.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Agda should not be used on Windows. None of the core release maintainers run Windows.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Strongly expects that you use Emacs, as Agda provides its own interactive Emacs mode.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;libraries&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Libraries&lt;/h2&gt;

&lt;p&gt;Apparently the Agda community is sufficiently small that all libraries (of significance?) can be listed comfortably on the main Agda website at &lt;a href=&quot;http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Libraries&quot;&gt;http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Libraries&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Informal sampling shows several libraries to be outdated,
not updated within the last 2 years.&lt;/li&gt;
&lt;li&gt;Therefore the number of actual &lt;em&gt;usable&lt;/em&gt; up-to-date libraries
is expected to be quite small, in the 4-7 range. Not promising.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Only two libraries under the &lt;a href=&quot;https://github.com/agda&quot;&gt;https://github.com/agda&lt;/a&gt; umbrella have been updated within the last year. One of them is the Agda standard library. Not a good sign of activity.&lt;/p&gt;

&lt;p&gt;Libraries do not carry external documentation. Instead all documentation is within the source code itself. The expectation is that you will use the Agda emacs mode to jump around between modules and explore to find what you want. Not ideal but serviceable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There seems to be some tool used to compile HTML that acts like the
Agda Emacs mode. In particular hyperlinking between modules is
supported.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Readers of the documentation are assumed to have high mathematical training. I see terms like &amp;ldquo;communative semiring&amp;rdquo;, &amp;ldquo;coinductive&amp;rdquo;, &amp;ldquo;lemma&amp;rdquo;, and &amp;ldquo;decidable&amp;rdquo;.&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;https://github.com/agda/agda-frp-js&quot;&gt;agda-frp-js&lt;/a&gt; &lt;small&gt;(last activity 2 years ago)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;This is an FRP implementation in Agda. I&amp;rsquo;ll look at it because I&amp;rsquo;ve been working in FRP systems recently (i.e. Elm). And because I&amp;rsquo;d like to see how well libraries are packaged by the Agda community.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Beh&amp;rdquo; is short for &amp;ldquo;behavior&amp;rdquo; and is equivalent to an Elm Signal.&lt;/p&gt;

&lt;p&gt;I note that there is no API documentation whatsoever for the module. You have to browse through the examples in the source tree manually. This suggests that either Agda has no doc generator tool (likely!) or this library author simply didn&amp;rsquo;t bother to generate docs for the public to read.&lt;/p&gt;

&lt;p&gt;Virtually no comments.&lt;/p&gt;

&lt;p&gt;Has own definition of Bool (booleans), RSet (function types), Int (integer types), and possibly other super primitive notions. This appears to be related to the use of the JavaScript backend, as most of these primitives have native JS code defined for many of these definitions.&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;https://github.com/agda/agda-frp-ltl&quot;&gt;agda-frp-ltl&lt;/a&gt; &lt;small&gt;(last activity 2 years ago)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;Not going to look at this closely due to the lack of activity.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;papers&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Papers&lt;/h2&gt;

&lt;p&gt;Agda is used in quite a number of academic papers. Certainly more papers than actual libraries, so far as I can tell. There&amp;rsquo;s a whole &lt;a href=&quot;http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.PapersUsingAgda&quot;&gt;list of papers that use Agda&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;http://ivanych.net/doc/SafeFunctionalProgrammingDependentTypes.pdf&quot;&gt;Safe Functional Reactive Programming through Dependent Types (2009)&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Describes an FRP system that is slightly more powerful than that of Yampa. It defines a type system around FRP that guarantees that FRP programs written within the type system will necessarily continue to make progress (i.e. not deadlock). (It is possible for an FRP system to deadlock if its signal graph get reconfigured into certain kinds of loops.) It also eliminates the distinction between continuous and discrete signals, reducing one class of errors. Furthermore it allows programs to include feedback loops and uninitialised signals in an FRP program, whilst guaranteeing evaluation progress at the type level.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;books&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Books&lt;/h2&gt;

&lt;p&gt;Hard to find books on Agda. I get nothing.&lt;/p&gt;

&lt;p&gt;However I do see some &lt;a href=&quot;http://stackoverflow.com/questions/13796557/books-about-coq&quot;&gt;books on Coq&lt;/a&gt;, which Agda is inspired by. Let&amp;rsquo;s not get distracted by those at the moment.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;other-resources&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Other Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf&quot;&gt;Dependently Typed Programming in Agda (2008)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Appears to be the original paper that introduced the Agda
programming language. Or at the very least a fairly complete
description of the language along with tutorial-style content.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.staff.science.uu.nl/~swier004/Publications/ThePowerOfPi.pdf&quot;&gt;The Power of Pi (2008)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Despite the indescriptive name, promises to show a number of design
patterns and techniques that apply to dependently types languages,
particularly Agda.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Dependent types matter. And not just for program verification
 and proof assistants: dependent types matter to programmers.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;This paper demonstrates how to program with dependent types.
 In particular, we present three case studies.
 Each case study describes a domain-specific language that is
 difficult to embed in conventional functional languages such
 as Haskell.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;design patterns of dependently-typed programming&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;domain-specific embedded type systems&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://oxij.org/note/BrutalDepTypes/&quot;&gt;Brutal (Meta)Introduction to Dependent Types in Agda&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Aims to describe at a high-level how dependently typed languages
work at the level of theory, without going into too many
details. Uses Agda as a concrete language to work with.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liamoc/learn-you-an-agda/blob/master/pages/introduction.md&quot;&gt;Learn You an Agda&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Already read this. Good high level introduction to the &lt;em&gt;promise&lt;/em&gt;
(or taste) of what&amp;rsquo;s possible in dependently typed languages.&lt;/li&gt;
&lt;li&gt;Difficult to browse, since the rendered HTML of these markdown
pages fell off the internet a while ago.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;p&gt;I first recognized that you could write this kind of provably correct sorting function when I read &lt;a href=&quot;http://www.cs.swan.ac.uk/~csetzer/lectures/intertheo/07/intertheodraft1.pdf&quot;&gt;these slides&lt;/a&gt; at &lt;a href=&quot;http://www.cs.swan.ac.uk/~csetzer/lectures/intertheo/07/interactiveTheoremProvingForAgdaUsers.html&quot;&gt;swan.ac.uk&lt;/a&gt;. You end up having a sorting function with a signature like &lt;code&gt;sort : (inList : List a) -&amp;gt; (outList : List a, IsSorted outList, EqElements inList outList)&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;The &lt;code&gt;IsSorted outList&lt;/code&gt; type represents proofs that &lt;code&gt;outList&lt;/code&gt; is sorted. Thus the existence of a member of the &lt;code&gt;IsSorted outList&lt;/code&gt; type proves that &lt;code&gt;outList&lt;/code&gt; is sorted. Similarly the &lt;code&gt;EqElements inList outList&lt;/code&gt; is a proof type where &lt;code&gt;inList&lt;/code&gt; and &lt;code&gt;outList&lt;/code&gt; are proven to have equal elements.&lt;/p&gt;&lt;p&gt;See also the &lt;a href=&quot;http://mazzo.li/posts/AgdaSort.html&quot;&gt;dedicated article at mazzo.li&lt;/a&gt;&lt;/p&gt;&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;None of the people who currently release Agda are running Windows according to the latest &lt;a href=&quot;http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.AIMXVIII&quot;&gt;Agda Implementors' Meeting&lt;/a&gt;.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/11/12/impressions-of-haskell</id>
   <title>Impressions of Haskell</title>
   <published>2013-11-12T00:00:00+00:00</published>
   <updated>2013-11-12T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/11/12/impressions-of-haskell/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I finally found an online tutorial for Haskell that involves writing a &lt;em&gt;non-trivial&lt;/em&gt; program:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://jonathan.tang.name/files/scheme_in_48/tutorial/functions.html&quot;&gt;Write Yourself a Scheme in 48 Hours&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It&amp;rsquo;s an excellent tutorial and has given me a good impression of Haskell for building a medium-sized non-trivial program: a LISP interpreter.&lt;/p&gt;

&lt;p&gt;This impression, however, has been more negative than positive. I would consider Haskell for use for doing programs that do heavy computation with pure functions alone.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; However if there&amp;rsquo;s any significant amount of I/O, error handling, or state, using Haskell is just bloody painful.&lt;/p&gt;

&lt;h3&gt;Monads are painful&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I/O must be done inside an I/O &lt;em&gt;monad&lt;/em&gt;.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Error handling must be done inside an error monad.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Passing around shared state must be done inside a state monad.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The preceding by itself would not be such a problem except that, in addition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Code that is pure uses a different syntax than code that is in a monad.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code that needs to be in multiple monads at the same time is a royal pain to write. It requires the use of &lt;em&gt;monad transformers&lt;/em&gt; and explicit converting (or &amp;ldquo;lifting&amp;rdquo;) between individual monads and combined monads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Having monadic code be in a different syntax than pure code requires the programmer to learn and use two different syntaxes. And these syntaxes aren&amp;rsquo;t even similar: they read in different directions. Mixing code that is both pure and monadic becomes confusing. Upgrading pure code to be monadic, which is not uncommon during development and maintenance, requires a lot of non-trivial syntactic transformations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pure code&lt;/strong&gt; - Reads inside-out, generally bottom-to-top and right-to-left.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monadic code&lt;/strong&gt; - Reads top-to-bottom (with do-notation) and left-to-right (with bind operations).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pure + monadic code&lt;/strong&gt; - Reads in multiple directions.&lt;/li&gt;
&lt;/ul&gt;


&lt;!--
&lt;ul class=&quot;nav nav-tabs&quot;&gt;
  &lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#pure&quot; data-toggle=&quot;tab&quot;&gt;Pure Code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#monadic&quot; data-toggle=&quot;tab&quot;&gt;Monadic Code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#mixed&quot; data-toggle=&quot;tab&quot;&gt;Pure + Monadic Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;tab-content&quot;&gt;
  &lt;div class=&quot;tab-pane fade in active&quot; id=&quot;pure&quot;&gt;
    &lt;p&gt;&lt;i&gt;Reads inside-out, generally bottom-to-top and right-to-left.&lt;/i&gt;&lt;/p&gt;
    &lt;p&gt;[TODO: code sample]&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class=&quot;tab-pane fade&quot; id=&quot;monadic&quot;&gt;
    &lt;p&gt;&lt;i&gt;Reads top-to-bottom (with do-notation) and left-to-right (with bind operations).&lt;/i&gt;&lt;/p&gt;
    &lt;p&gt;[TODO: code sample]&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class=&quot;tab-pane fade&quot; id=&quot;mixed&quot;&gt;
    &lt;p&gt;&lt;i&gt;Reads in multiple directions.&lt;/i&gt;&lt;/p&gt;
    &lt;p&gt;[TODO: code sample]&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
--&gt;


&lt;p&gt;Using a pure value within monadic code requires you to &amp;ldquo;lift&amp;rdquo; the pure value into a monad value with an explicit conversion. Similarly using a monadic value in multi-monadic code (created by a monad transformer) requires you to lift the monadic value into a multi-monad value first. These explicit conversions pepper and obscure the main program logic. One has to do an annoying amount of gymnastics to make the type system happy.&lt;/p&gt;

&lt;h3&gt;Code golf erodes readability&lt;/h3&gt;

&lt;p&gt;Another factor complicating the readability of code is the Haskell community&amp;rsquo;s propensity for &lt;em&gt;code golf&lt;/em&gt;: the tendancy to write code that is especially terse to the point of making it difficult to understand. There are many language and library features in Haskell that enable this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overuse of operator overloading and custom operators:

&lt;ul&gt;
&lt;li&gt;The ability to mix custom infix and prefix operators in the same expression. Confusing.&lt;/li&gt;
&lt;li&gt;The ability to treat an infix operator as prefix or visa-versa, when using certain syntax. Inconsistent.&lt;/li&gt;
&lt;li&gt;The usage of custom operators in ambiguous fashion requiring knowledge of either the operator associativity or precedence to disambiguate. Requires non-local knowledge to parse expressions.

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For example the &lt;code&gt;$&lt;/code&gt; operator appears to be a precedence hack to avoid the need to parenthesize an expression properly. I don&amp;rsquo;t think it worth introducing tricky syntax to avoid typing a single close paren.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Implicit partial application of functions. Infix operator sections.

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You must know the arity of a function to determine what an expression containing that function means.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; Requires non-local knowledge to parse expressions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Point-free style.

&lt;ul&gt;
&lt;li&gt;Discourages the use of explaining variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Terseness at the expense of readability was a hallmark of Perl. I don&amp;rsquo;t find it any more attractive in Haskell.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a short example containing monadic code, point-free style, and an operator section.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-- Parses the expression in the first argument to the program, evaluates it, and prints the result.
main :: IO ()
main = getArgs &amp;gt;&amp;gt;= putStrLn . show . eval . readExpr . (!! 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I argue that the preceding code is manifestly confusing for any newcomer to Haskell, yet this type of code I see frequently in Haskell written by others.&lt;/p&gt;

&lt;p&gt;It is possible to rewrite the code to be more explicit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;main = do args &amp;lt;- getArgs
          putStrLn (show (eval (readExpr (args !! 0))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Although I think the preceding would not be considered idiomatic Haskell.&lt;/p&gt;

&lt;h3&gt;The end?&lt;/h3&gt;

&lt;p&gt;Haskell&amp;rsquo;s strong type system and heavy restrictions on mutable state provide good assurance that the programs you write are correct, assuming you manage to write the program in the first place.&lt;/p&gt;

&lt;p&gt;However I find Haskell difficult to write (due to monads and the type system) and difficult to read (due to code golf). I also do not require such a high assurance of correctness in the domains I work in. I typically find that a disciplined minimization of mutable state in other languages is sufficent to provide the necessary level of correctness I require, and with more flexibility during maintenance.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Types of programs I might consider doing in Haskell include, for example, maze generators, Sudoku solvers (non-visual), parsers, and compilers. Games involving lots of state such as platformers, adventure games, or anything with multiple screens would be a pain. GUIs and other interactive programs based on events would be a pain.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;A &lt;em&gt;monad&lt;/em&gt; is a particular pattern of sequencing computation involving the type system. The use of monads is unique to Haskell so far as I am aware.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Granted it is possible to handle errors using &lt;a href=&quot;http://hackage.haskell.org/package/base-4.6.0.1/docs/Control-Exception.html#v%3athrow&quot;&gt;&lt;code&gt;throw&lt;/code&gt;&lt;/a&gt; but this is discouraged because it yields non-deterministic ordering with respect to I/O operations. It is also possible to use &lt;a href=&quot;http://hackage.haskell.org/package/base-4.6.0.1/docs/Control-Exception.html#v%3athrowIO&quot;&gt;&lt;code&gt;throwIO&lt;/code&gt;&lt;/a&gt; but only if the function is already in the IO monad. Should the function be otherwise pure, you&amp;rsquo;d be forced to &amp;ldquo;infect&amp;rdquo; it with the IO monad in order to use &lt;code&gt;throwIO&lt;/code&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;Of course you could just incorporate the shared state into the parameters and return type of all functions, but this gets annoying fast. Granted it is possible to use &lt;a href=&quot;http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-IORef.html&quot;&gt;&lt;code&gt;IORef&lt;/code&gt;s&lt;/a&gt; if the function using state is already in the IO monad. Should the function be otherwise pure, you&amp;rsquo;d be forced to &amp;ldquo;infect&amp;rdquo; it with the IO monad in order to use &lt;code&gt;IORef&lt;/code&gt;s.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;&lt;p&gt;I wrote an &lt;a href=&quot;/articles/2013/05/12/implicit-partial-application-and-currying-considered-harmful/&quot;&gt;entire article&lt;/a&gt; on just this point of implicit partial application being confusing. Unfortunately I think r/haskell was confused by my argument.&lt;/p&gt; &lt;p&gt;Consider the expression &lt;code&gt;f 3&lt;/code&gt; by itself, possibly part of a larger expression like &lt;code&gt;f 3 $ g&lt;/code&gt;. In a typical language I consider functions to be entities that take some fixed number of arguments and then produce a single result. This means that if I encounter a well-named function &lt;code&gt;f&lt;/code&gt; that I haven&amp;rsquo;t seen before, I can usually guess from its name what it does and what its return type is. I can also assume that an expression like &lt;code&gt;f 3&lt;/code&gt; will evaluate to this assumed return type.&lt;/p&gt; &lt;p&gt;In Haskell I cannot make that assumption: Support for implicit partial function application might mean that an expression &lt;code&gt;f 3&lt;/code&gt; might not evaluate to the return type of &lt;code&gt;f&lt;/code&gt;. I have to ask myself &amp;ldquo;Does it look like this function needs more arguments here to perform the action that its name suggests?&amp;rdquo;. If the answer is yes then I assume that the expression evaluates to a new function with some unknown number of arguments with the return type I expect. That&amp;rsquo;s very confusing. I object to the possibility that two function applications that begin with &lt;code&gt;f 3 ...&lt;/code&gt; could return different types of values.&lt;/p&gt;&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/09/30/strange-loop-2013-highlights</id>
   <title>Strange Loop 2013 Highlights</title>
   <published>2013-09-30T00:00:00+00:00</published>
   <updated>2013-09-30T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/09/30/strange-loop-2013-highlights/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;This year I attended &lt;a href=&quot;https://thestrangeloop.com/&quot;&gt;Strange Loop&lt;/a&gt;, a conference on emerging tools, languages, and trends in software. I found the following sessions to be most interesting.&lt;/p&gt;

&lt;p&gt;Session videos are available for attendees now, and for the general public closer to March 2014.&lt;/p&gt;

&lt;h2&gt;Emerging Languages Camp&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/noether&quot;&gt;&lt;strong&gt;Noether: Symmetry in Programming Language Design&lt;/strong&gt;&lt;/a&gt; - Daira Hopwood - 45 min

&lt;ul&gt;
&lt;li&gt;A language system, composed of several different language levels, each level breaking successively more symmetries to gain expressive power at the expense of static reasoning about the program&amp;rsquo;s behavior. Very flexible.&lt;/li&gt;
&lt;li&gt;This is the only language presented during the Emerging Languages Camp that had a strong theoretical foundation.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I will definitely be looking into this language family when it has been implemented.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/nimrod&quot;&gt;&lt;strong&gt;Nimrod: A new approach to meta programming&lt;/strong&gt;&lt;/a&gt; - Andreas Rumpf - 25 min

&lt;ul&gt;
&lt;li&gt;A new statically-typed systems language. Full-featured.&lt;/li&gt;
&lt;li&gt;Already has non-trivial tooling, such as an IDE.&lt;/li&gt;
&lt;li&gt;Has a realtime garbage collector, macros, whole program dead code elimination, and generics.&lt;/li&gt;
&lt;li&gt;Can automatically promote sideeffect-free functions to &lt;em&gt;compile&lt;/em&gt;-time execution.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compile-time optimizations on the AST can be coded directly in Nimrod. This is similar to macros but acts like a global peephole optimization. Very powerful.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/j-language&quot;&gt;&lt;strong&gt;The J Programming Language&lt;/strong&gt;&lt;/a&gt; -  Tracy Harms - 27 min

&lt;ul&gt;
&lt;li&gt;An array-based data language.&lt;/li&gt;
&lt;li&gt;Successor to the famous &lt;a href=&quot;https://en.wikipedia.org/wiki/APL_(programming_language)&quot;&gt;APL language&lt;/a&gt;, which allows very succinct representations of numeric computations. Although extremely hard to read for those unfamiliar with the syntax:

&lt;ul&gt;
&lt;li&gt;Find all prime numbers: &lt;code&gt;(~R∊R∘.×R)/R←1↓ιR&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Conway&amp;rsquo;s Game of Life: &lt;code&gt;life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you&amp;rsquo;ve never used an array-based numerical language before, this is a great beginner&amp;rsquo;s introduction.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/bodol&quot;&gt;&lt;strong&gt;BODOL, or How To Accidentally Build Your Own Language&lt;/strong&gt;&lt;/a&gt; - Bodil Stokke - 42 min

&lt;ul&gt;
&lt;li&gt;A guide to implementing your own language on top of Clojure.&lt;/li&gt;
&lt;li&gt;A very entertaining presentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;strong&gt;Honorable Mention:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/qbrt-bytecode&quot;&gt;&lt;strong&gt;Qbrt Bytecode: Interface Between Code and Execution&lt;/strong&gt;&lt;/a&gt; - Matthew Graham - 26 min

&lt;ul&gt;
&lt;li&gt;A bytecode assembly language with builtin primitives for concurrency and inline asynchronous I/O.&lt;/li&gt;
&lt;li&gt;I liked the presentation itself although I&amp;rsquo;m not sure I&amp;rsquo;d want to use Qbert for any of my own projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Unsessions&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QuickCheck&lt;/strong&gt; - no video available

&lt;ul&gt;
&lt;li&gt;QuickCheck is a testing tool that automatically generates test cases for a program given a description of its inputs, outputs, and expected semantics. Quite powerful.&lt;/li&gt;
&lt;li&gt;When a failing test case is found, QuickCheck is able to automatically reduce the test case to the &lt;em&gt;minimal&lt;/em&gt; reproducing test case. Extremely useful.&lt;/li&gt;
&lt;li&gt;Although QuickCheck was originally written for Haskell, there are now ports to several other languages.&lt;/li&gt;
&lt;li&gt;There a commercial versions of QuickCheck that are superior to the open-source versions in a few ways.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Sessions &amp;amp; Themes&lt;/h2&gt;

&lt;h3&gt;Async &lt;small&gt;(Reducing callback hell)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;If you only watch one of these presentations, pick the Clojure one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Async in C# and F#&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Although not presented at Strange Loop, the implementation of the &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords in C# and F# seems to have greatly inspired similar mechanisms in other languages.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; avoids the callback hell problem often seen in JavaScript, where a series of nested callbacks just keeps increasing the indentation level of the code. And callbacks in the midst of complex control flow like loops are even more problematic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/scala-async&quot;&gt;&lt;strong&gt;Async in Scala&lt;/strong&gt;&lt;/a&gt; - Philipp Haller - 44 min

&lt;ul&gt;
&lt;li&gt;Similar to async/await in C# and F#.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented in Scala as a macro, using the experimental support for Scala macros.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/clojure-core-async&quot;&gt;&lt;strong&gt;Async in Clojure: Channels &amp;amp; Queues&lt;/strong&gt;&lt;/a&gt; - Rich Hickey - 44 min

&lt;ul&gt;
&lt;li&gt;Appears to be different in spirit to the async-implementation in other languages: Seems to be intended for implementing &lt;em&gt;channels&lt;/em&gt; (from the Go language), rather than attempting to target the callback hell problem.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The presentation itself has some interesting general thoughts on concurrency in software.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async in Python&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Again, not presented at Strange Loop, but it appears that the &lt;code&gt;yield from&lt;/code&gt; expression in Python 3 can be used to implement C#/F#-style async/await. I need to look into this.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Creativity and Artificial Intelligence&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/ai-machine-creativity&quot;&gt;&lt;strong&gt;Creative Machines&lt;/strong&gt;&lt;/a&gt; - Joseph Wilk - 41 min

&lt;ul&gt;
&lt;li&gt;Interesting philosohpical discussion on how computers can create creative things.&lt;/li&gt;
&lt;li&gt;Teaching computers to play music.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Joseph&amp;rsquo;s program for creating music compositions makes, in his opinion, better music than he could compose himself. This brings up the interesting observation that a student, in this case a computer, can surpass the teacher. This is not unheard of when both teacher and student are human, but it&amp;rsquo;s a bit uncomfortable to conventional thinking when the student is a &amp;ldquo;soulless&amp;rdquo; or &amp;ldquo;non-understanding&amp;rdquo; computer and the teacher is a &amp;ldquo;sentient&amp;rdquo; human.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/nintendo-automation&quot;&gt;&lt;strong&gt;Learnfun and Playfun: A Nintendo automation system&lt;/strong&gt;&lt;/a&gt; - Tom Murphy VII - 28 min

&lt;ul&gt;
&lt;li&gt;Teaching computers to play video games.&lt;/li&gt;
&lt;li&gt;I found it particularly amusing that the computer learned to manipulate the random number generator (by pausing the game for calculated periods) to create its own luck. In pinball games this allowed the computer to play perfectly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Theory Meets Practice&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/data-types-issues&quot;&gt;&lt;strong&gt;The Trouble With Types&lt;/strong&gt;&lt;/a&gt; - Martin Odersky - 49 min

&lt;ul&gt;
&lt;li&gt;A balanced description of static vs. dynamic types, a classic debate in computing.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Martin himself, being the creator of Scala, is firmly in the static typing camp but still provides a good overview of when dynamic typing is useful as well.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/abstract-algebra-analytics&quot;&gt;&lt;strong&gt;Add ALL the things: abstract algebra meets analytics&lt;/strong&gt;&lt;/a&gt; - Avi Bryant - 37 min

&lt;ul&gt;
&lt;li&gt;A good introduction to parts of category theory, using analytics systems for concrete examples throughout the talk.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There was another presentation on category theory at Strange Loop but I found this talk far easier to follow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/reimagining-software&quot;&gt;&lt;strong&gt;Finding a way out&lt;/strong&gt;&lt;/a&gt; - Chris Granger - 33 min

&lt;ul&gt;
&lt;li&gt;Thoughts on the future of programming and how it can be made better.&lt;/li&gt;
&lt;li&gt;The second half of the presentation walks through a demo of Aurora, a new alpha-stage tool that Chris is working on, incorporating some of Chris&amp;rsquo;s new thoughts on the programming process.&lt;/li&gt;
&lt;li&gt;Chris Granger is the creator of Light Table, a visual programming environment that attempts to bring improved interactivity and feedback to the development process. Light Table is inspired by Bret Victor&amp;rsquo;s excellent talk &lt;a href=&quot;http://vimeo.com/36579366&quot;&gt;Inventing on Principle&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Tools&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/javascript-asmjs&quot;&gt;&lt;strong&gt;Native Speed on the Web: JavaScript and asm.js&lt;/strong&gt;&lt;/a&gt; - Alon Zakai - 30 min

&lt;ul&gt;
&lt;li&gt;Useful overview of asm.js, which can compile C/C++ to fast JavaScript.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This capability is very exciting since it can connect programs written for the traditional desktop environment to the web deployment platform. For example my efforts at making old Mac software easy to emulate on modern hardware, which currently requires installation on a desktop computer, could be altered to be widely deployable to the web.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/birth-death-javascript&quot;&gt;&lt;strong&gt;The Birth &amp;amp; Death of JavaScript&lt;/strong&gt;&lt;/a&gt; - Gary Bernhardt - 20 min (without comments) or 40 min (with)

&lt;ul&gt;
&lt;li&gt;A very creative presentation on how asm.js could be used to make major changes to computing, bringing all traditional desktop applications to the browser.&lt;/li&gt;
&lt;li&gt;Uses the narrative style of presenting as if from a different time period, also used to great effect in Bret Victor&amp;rsquo;s talk on &lt;a href=&quot;http://vimeo.com/71278954&quot;&gt;The Future of Programming&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Minorities in Computing&lt;/h3&gt;

&lt;h4&gt;Women&lt;/h4&gt;

&lt;p&gt;It&amp;rsquo;s been known for some time that women are strongly underrepresented in computing. I know they&amp;rsquo;re falling out of the training pipeline early as I receive almost no women applicants to the Splunk Seattle office.&lt;/p&gt;

&lt;p&gt;So far the primary discouraging factors I&amp;rsquo;ve been able to identify include a lack of female role models in software and a hostile learning environment created by guys when girls try to enter the field.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/software-development-everyone&quot;&gt;&lt;strong&gt;Making Software Development Make Sense to Everyone&lt;/strong&gt;&lt;/a&gt; - Jen Myers - 58 min

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Very informative. Full of data and ideas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rails Girls: Empowering women through code&lt;/strong&gt; - Adriana Palacio, Laura Garcia - 13 min

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Key takeaway is that there are a lack of female role models in computing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/history-women-technology&quot;&gt;&lt;strong&gt;The History of Women in Technology&lt;/strong&gt;&lt;/a&gt; - Sarah Dutkiewicz - 40 min

&lt;ul&gt;
&lt;li&gt;Reviews a number of important women in computing. Unfortunately very few from the modern era.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Kids&lt;/h4&gt;

&lt;p&gt;It is also difficult to get kids into computing. No longer are computers widely shipped with BASIC interpreters, HyperCard, or other well-designed introductory programming environments that kids can just jump into. Additionally the bar for what is considered an acceptable game or program has risen considerably, making it harder to get excited about simple programs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/hopscotch&quot;&gt;&lt;strong&gt;How to teach your kid to code with Hopscotch&lt;/strong&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Hopscotch is a visual programming language for the iPad designed to help kids get started with programming.&lt;/li&gt;
&lt;li&gt;Another system for introducing kids to programming is &lt;a href=&quot;http://scratch.mit.edu/&quot;&gt;Scratch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Notes:

&lt;ul&gt;
&lt;li&gt;Finding good &lt;em&gt;ideas&lt;/em&gt; for programs is tricky. For kids, ideas have to be applicable to their cultural context. Drawing things is more interesting than scraping Twitter.&lt;/li&gt;
&lt;li&gt;Making all available tools and commands &lt;em&gt;visible&lt;/em&gt; is important for a system designed for learning.&lt;/li&gt;
&lt;li&gt;The game of &amp;ldquo;program your parent&amp;rdquo; is amusing.&lt;/li&gt;
&lt;li&gt;Traditional editors, code, and IDEs actually look rather intimidating to new users. It&amp;rsquo;s like a non-aviation operator being confronted with the full control panel of an airplane cockpit.&lt;/li&gt;
&lt;li&gt;Poor typing skills is a non-trivial barrier for young kids.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Other&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/style-methodology&quot;&gt;&lt;strong&gt;Exercises in Style&lt;/strong&gt;&lt;/a&gt; - Crista Lopes - 39 min

&lt;ul&gt;
&lt;li&gt;A fascinating experient where the same program is written in several different styles.&lt;/li&gt;
&lt;li&gt;This experiment makes it obvious that not only are there lots of ways of writing the same program, but also that different languages encourage different styles.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The material in this presentation will eventually be incorporated into a book &lt;a href=&quot;http://www.amazon.com/gp/product/1482227371/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1482227371&amp;amp;linkCode=as2&amp;amp;tag=dafo07-20&quot;&gt;Exercises in Programming Style&lt;/a&gt; that will be released in Spring of 2014. I&amp;rsquo;m definitely getting a copy.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/php-history&quot;&gt;&lt;strong&gt;Taking PHP Seriously&lt;/strong&gt;&lt;/a&gt; - Keith Adams - 40 min

&lt;ul&gt;
&lt;li&gt;Reviews the &lt;em&gt;good&lt;/em&gt; parts of PHP.&lt;/li&gt;
&lt;li&gt;Introduces Hack, a gradually-typed version of PHP that in production use at Facebook.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The HipHop project also includes a lot of useful tools such as a debugger, profiler, and IDE integration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;!--
* [**Programming a 144-computer chip to minimize power**](http://www.infoq.com/presentations/power-144-chip) - Chuck Moore - 40 min
    * A custom hardware programming environment for programming very low power applications.
    * Easily the lowest-level talk at the conference. Basically involves using a custom assembly language. Includes tips and tricks to optimize the assembly for the hardware and power.
    * Skip this presentation if low-level programming and bit twiddling isn't your thing.
--&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/09/04/regular-expressions</id>
   <title>Regular Expressions</title>
   <published>2013-09-04T00:00:00+00:00</published>
   <updated>2013-09-04T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Productivity"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/09/04/regular-expressions/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Regular expressions are a concise way to search and transform strings using patterns. They are available in numerous text editors and programming languages.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2013/09/04/regular-expressions/&quot;&gt;Read more&amp;hellip;&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/08/25/how-i-learn-new-programming-languages</id>
   <title>How I learn new programming languages</title>
   <published>2013-08-25T00:00:00+00:00</published>
   <updated>2013-08-25T00:00:00+00:00</updated>
   
     <category term="Personal"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/08/25/how-i-learn-new-programming-languages/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I don&amp;rsquo;t learn new programming languages very often. It simply requires an enormous amount of time to properly understand the local philosophy, community, tools, and ecosystem. But every so often I see a glimmer in an unfamilar language that merits me picking it up.&lt;/p&gt;

&lt;p&gt;Very recently I decided to learn Clojure to fulfill my future needs for a high-power language&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Before embarking on this journey, I thought it would be valuable to reflect on how I&amp;rsquo;ve learned other languages in the past and why I learned them.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#my-journey&quot;&gt;My Journey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#patterns-of-learning&quot;&gt;Patterns of Learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#appendix&quot;&gt;Appendix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;my-journey&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;My Journey&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HyperTalk &amp;amp; HyperCard&lt;/strong&gt; &amp;ndash; Play

&lt;ul&gt;
&lt;li&gt;This was my first programming language, first used at age 6.&lt;/li&gt;
&lt;li&gt;The HyperCard environment was sufficiently well designed that I could &lt;em&gt;play&lt;/em&gt; with existing programs, copy bits and pieces to assemble my own, and eventually build components from scratch.&lt;/li&gt;
&lt;li&gt;The physicality of the system, the straightforward syntax, and the composability of program elements enabled this kind of play. I do not know of any programming environments today in which this would be possible.

&lt;ul&gt;
&lt;li&gt;Visual Basic is promising, although I&amp;rsquo;ve never used it. It has physicality and native graphics.&lt;/li&gt;
&lt;li&gt;DarkBASIC is also promising for making 3D games, although I haven&amp;rsquo;t used it for anything serious. It has native 3D graphics.&lt;/li&gt;
&lt;li&gt;Python has a REPL that you can experiment with and has reasonably straightforward and consistent syntax. However it has no native graphics and no physicality.&lt;/li&gt;
&lt;li&gt;Processing has a built-in graphics. But it&amp;rsquo;s not designed for composability at all, meaning that you can&amp;rsquo;t mix and match parts from different programs. Its function naming is also haphazard and inconsistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My game &lt;a href=&quot;/prism/projects/dungeons/&quot;&gt;Dungeons&lt;/a&gt; was the most advanced program I wrote in HyperCard. Other kids at National Computer Camp would line up at my computer who wanted to play it. I was very proud.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BASIC, Pascal&lt;/strong&gt; &amp;ndash; Instructional Setting

&lt;ul&gt;
&lt;li&gt;At age 8 I picked these languages up at National Computer Camp because the instructors insisted on learning them before going on to other languages. &lt;!-- With my prior two years of HyperTalk and general programming experience, I blew through these languages very quickly. --&gt;&lt;/li&gt;
&lt;li&gt;These were my first compiled languages.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Neither of these languages were distinctive enough for me to keep using.&lt;br/&gt;
I did no major projects in these languages.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C, C++&lt;/strong&gt; &amp;ndash; Brute Force, Instructional Setting

&lt;ul&gt;
&lt;li&gt;I learned these to interface directly with the Mac operating system and to do programs in color, since HyperCard only supported black &amp;amp; white graphics.&lt;/li&gt;
&lt;li&gt;I also had some instructional assistance at National Computer Camp during the summer.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I wish I could remember how I internalized pointers and manual memory management, since these are some of the most confusing bits of these languages for beginners. And most annoying for experts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java&lt;/strong&gt; &amp;ndash; Brute Force

&lt;ul&gt;
&lt;li&gt;I initially learned Java in 2001 when I tried to write RealMediaFixer in C++.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; When doing this I discovered that CodeWarrior&amp;rsquo;s buffered I/O implementation was busted on Mac OS, behaving in a nondeterministic fashion. So I picked the most similar-looking language to C++ I&amp;rsquo;d heard of, namely Java, and ported RealMediaFixer to use it instead. It worked on the first try and I didn&amp;rsquo;t look back to C++ for several years. (After all, why would I use a language where &lt;em&gt;I/O&lt;/em&gt; was broken?)&lt;/li&gt;
&lt;li&gt;I just wrote tons and tons of programs in Java for the next 8 years or so, through the rest of middle school, high school, and college.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;I also had some early instructional assistance at National Computer Camp. I am forever grateful to whatever instructor introduced me to the &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/&quot;&gt;Java API documentation&lt;/a&gt;, allowing me to teach myself arbitrary parts of the Java standard library without relying on books or tutorials. Once you can teach yourself, the learning game is really on.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My Java decompiler &lt;a href=&quot;/prism/projects/decomp/&quot;&gt;decomp4&lt;/a&gt; was the most advanced program I wrote in Java.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; &amp;ndash; Targeted Large Projects

&lt;ul&gt;
&lt;li&gt;While interning at Google in 2008 I noticed that they had three primary languages: Java, C++, and Python. Since Google engineers were the smartest group of developers I&amp;rsquo;d ever run into, I figured they might be on to something with Python. So I started reading about Python and its capabilities.&lt;/li&gt;
&lt;li&gt;My first attempt at a real program was the implementing of DiskSurveyorX in late 2008, a disk space visualizer.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; Unfortunately the best GUI toolkit available in Python, wxPython, I found to be far too clunky to use. So I ended up reverting to implementing in Java using the Swing toolkit.&lt;/li&gt;
&lt;li&gt;My second and successful attempt to write a substantial Python program was &lt;a href=&quot;/projects/crystal-web-archiver/&quot;&gt;Crystal Web Archiver&lt;/a&gt; in late 2011, a website downloader and archival system.

&lt;ul&gt;
&lt;li&gt;Again I had to use wxPython. This time though I ended up writing an abstraction layer over the worst parts to remove much of the pain.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python is currently my favorite language for general purpose programming. Particularly for scripting, data analysis, and other kinds of exploratory work.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript&lt;/strong&gt; &amp;ndash; Socialization, Brute Force (via Employment)

&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;ve been using JavaScript, HTML, and CSS since mid-2012 to create rich web applications, primarily in the form of Splunk&amp;rsquo;s app development framework. JavaScript was chosen because it is the lingua-franca of web development and because of its enormous leveragable ecosystem of libraries such as JQuery, Backbone, and Bootstrap.&lt;/li&gt;
&lt;li&gt;Advanced JavaScript is almost impossible to learn on your own because there is no patron company that controls it nor is there a Benevolent Dictator for Life to provide officially blessed documentation or tutorials for how to use the language effectively. And this language has a sufficiently large number of design flaws that you need to learn to use it in a &lt;em&gt;disciplined&lt;/em&gt; fashion.&lt;/li&gt;
&lt;li&gt;I wouldn&amp;rsquo;t have been able to get far in JavaScript without help from my coworker Itay who was already proficient. Should you not have access to such a resource probably the next-best thing is to look for non-trivial projects on Github and read them. For example I learned a lot by playing with &lt;a href=&quot;http://browserquest.mozilla.org/&quot;&gt;BrowserQuest&lt;/a&gt; and reading its &lt;a href=&quot;https://github.com/mozilla/BrowserQuest&quot;&gt;source code&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;patterns-of-learning&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Patterns of Learning&lt;/h2&gt;

&lt;p&gt;The primary patterns observed in my learning journey above include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Play&lt;/strong&gt; &amp;ndash; undirected learning, by oneself

&lt;ul&gt;
&lt;li&gt;This only works well with exceptionally well-designed programming environments. Sadly there are very few modern environments that fit the bill.

&lt;ul&gt;
&lt;li&gt;HyperCard is dead. Visual Basic is dying. DarkBASIC is not well known.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Processing and Racket work okay but have some issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brute Force&lt;/strong&gt; &amp;ndash; writing lots and lots of programs

&lt;ul&gt;
&lt;li&gt;This method will certainly give you the most understanding. It also takes the most time.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Having access to a mentor to check your work is useful but not required.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Targeted Large Projects&lt;/strong&gt; &amp;ndash; writing a small number of projects geared toward getting the most experience

&lt;ul&gt;
&lt;li&gt;This is similar to the &amp;ldquo;brute force&amp;rdquo; approach but is more &lt;a href=&quot;http://expertenough.com/1423/deliberate-practice&quot;&gt;tactical&lt;/a&gt;. It also requires more mental effort.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;These primary patterns are coupled with a few secondary patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Instructional Setting&lt;/strong&gt; &amp;ndash; taking a class to learn basic and intermediate skills

&lt;ul&gt;
&lt;li&gt;I only found taking classes to be useful when my programming foundations were weak. Such classes provide very little value to me today.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Note that taking a class isn&amp;rsquo;t enough by itself. You have to practice on your own outside the class and after the class is finished.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Socialization&lt;/strong&gt; &amp;ndash; working with other developers to learn intermediate and advanced skills

&lt;ul&gt;
&lt;li&gt;Some things you can only learn efficiently from other developers.&lt;/li&gt;
&lt;li&gt;Socialization is particularly useful for learning things in a highly fragmented ecosystem (such as JavaScript) or in settings with advanced concepts (such as overall program architecture or the functional programming paradigm).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;appendix&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Appendix&lt;/h2&gt;

&lt;p&gt;There are a few languages I learned enough of to decide they weren&amp;rsquo;t worth using in new projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PHP&lt;/strong&gt; &amp;ndash; most widely deployed server-side web language

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/&quot;&gt;Just say no.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ruby&lt;/strong&gt; &amp;ndash; used primarily as a server-side web language

&lt;ul&gt;
&lt;li&gt;Insufficiently distinct from Python.&lt;/li&gt;
&lt;li&gt;Poor backward compatibility guarantees. No release notes.&lt;/li&gt;
&lt;li&gt;Sloppy design: &lt;a href=&quot;http://madhadron.com/posts/2014-11-10-languages_for_humans_and_subhumans.html&quot;&gt;Non-formal grammar.&lt;/a&gt; Syntax schizophrenia. Monkeypatching accepted as a valid practice. Mutable strings. &lt;!-- Non-uniform string representation. --&gt;&lt;/li&gt;
&lt;li&gt;But superior packaging, dependency management, and isolation systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes unique features of several languages mentioned in this article.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Paul Graham&amp;rsquo;s essays on &lt;a href=&quot;http://www.paulgraham.com/icad.html&quot;&gt;Lisp and language power&lt;/a&gt; are a thought-provoking read. By my assessment the current most-powerful languages out there are &lt;a href=&quot;http://www.haskell.org/&quot;&gt;Haskell&lt;/a&gt; and various members of the Lisp family (ex: Scheme, &lt;a href=&quot;http://racket-lang.org/&quot;&gt;Racket&lt;/a&gt;, &lt;a href=&quot;http://clojure.org/&quot;&gt;Clojure&lt;/a&gt;). I&amp;rsquo;ve decided to pass over Haskell for the time being for a number of reasons, particularly because of its high learning curve. I will probably return to it eventually.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;strong&gt;RealMediaFixer&lt;/strong&gt; was a program I wrote that repaired RealMedia (&lt;code&gt;.rm&lt;/code&gt;) files playable in RealPlayer. Such files downloaded over dialup would often get subtlely corrupted. Since downloading a 30-minute video could easily take a day it was more practical to try repairing the broken file rather than redownloading it.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;I have a huge trove of Java programs from this time period I&amp;rsquo;d like to publish some day. A very small subset of these programs are listed on &lt;a href=&quot;/prism/projects/&quot;&gt;my old projects page&lt;/a&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;&lt;strong&gt;DiskSurveyorX&lt;/strong&gt; was a disk space visualizer program that used similar visualizations as the original DiskSurveyor program for classic Mac OS. It however had some nice usability improvements pulled from my learnings from the information visualization class I took at the Technische Universität München. A modern disk space visualizer that uses a similar visualization is &lt;a href=&quot;http://www.daisydiskapp.com/&quot;&gt;DaisyDisk&lt;/a&gt;, which I highly recommend.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;For desktop GUI development, the Java + Swing combination is still my favorite. Followed closely by the Objective-C + Cocoa + Mac combination. I don&amp;rsquo;t care about GUI programs on Windows or Linux. However now practically all GUI development is going to the web, where solutions based on HTML + CSS + JavaScript reign supreme.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/08/19/interactive-computing</id>
   <title>Interactive Computing</title>
   <published>2013-08-19T00:00:00+00:00</published>
   <updated>2013-08-19T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/08/19/interactive-computing/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I spent a considerable amount of time yesterday going through the work of &lt;a href=&quot;http://worrydream.com/&quot;&gt;Bret Victor&lt;/a&gt;, who appears to be on a personal mission to bring interactive computing to mainstream developers. The tools he&amp;rsquo;s prototyping and building are just incredible.&lt;/p&gt;

&lt;p&gt;What the heck do I mean by &lt;em&gt;interactive computing&lt;/em&gt; you ask? This is perhaps best demonstrated by examples from Bret&amp;rsquo;s portfolio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://vimeo.com/36579366&quot;&gt;&lt;strong&gt;Inventing on Principle&lt;/strong&gt;&lt;/a&gt; (54 minutes)

&lt;ul&gt;
&lt;li&gt;Shows 5 different demos where Bret has programs or other complex objects where he can tweak the object at runtime and get immediate feedback. This is incredibly empowering.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It makes me feel that a lot of the developer tools I&amp;rsquo;ve been using are obsolete. Particularly for advanced applications that involve the analysis and exploration of data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://worrydream.com/LadderOfAbstraction/&quot;&gt;&lt;strong&gt;Up and Down the Ladder of Abstraction&lt;/strong&gt;&lt;/a&gt; (13 pages)

&lt;ul&gt;
&lt;li&gt;Shows how an algorithm based on tunable parameters can be inspected and modified at runtime with immediate feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;By happenstance I&amp;rsquo;ve been fighting the problem of lacking immediate feedback recently: I&amp;rsquo;ve been writing a number of tools for processing complex semi-structured information where the algorithms needed a lot of tweaking.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; To gain a limited form of live tweaking I wrote a &lt;a href=&quot;http://dafoster.net/articles/2013/08/13/fixing-a-function-at-runtime-without-restarting-the-program/&quot;&gt;function decorator&lt;/a&gt; that allowed me to modify and reload functions at runtime without interrupting the program. The tools that Bret is prototyping are considerably more advanced than this, allowing changes to individual expressions without even a reload step.&lt;/p&gt;

&lt;p&gt;Other small steps in the direction of interactivity in mainstream environments include the display of non-text results in interactive prompts. The &lt;a href=&quot;http://ipython.org/notebook.html&quot;&gt;IPython&lt;/a&gt; environment, for example, allows image values to be displayed directly in interactive prompts. This is great for statistical visualizations on complex datasets and for image processing functions. The &lt;a href=&quot;http://docs.racket-lang.org/quick/index.html&quot;&gt;Racket&lt;/a&gt; environment (a Scheme/Lisp dialect) also supports direct display of image values. It would be nice if HTML elements, sound waveforms, and video objects were also directly displayable.&lt;/p&gt;

&lt;p&gt;The recent work on the &lt;a href=&quot;http://www.chris-granger.com/2012/04/12/light-table---a-new-ide-concept/&quot;&gt;Light Table&lt;/a&gt; web IDE is directly inspired by Bret&amp;rsquo;s work, which I didn&amp;rsquo;t realize the first time I heard about it. And now I notice that Light Table has support for Python&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; in addition to the original Clojure and JavaScript/HTML languages. Sweet.&lt;/p&gt;

&lt;p&gt;Exciting developments.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;In case you&amp;rsquo;re wondering, these tools are designed to scrape various kinds of data from popular websites. I&amp;rsquo;m experimenting with the idea of making it easy to extract structured information out of semi-structured websites. If it was trivially easy to get data out of websites, what could you do with it? What new mashups and applications would arise that you didn&amp;rsquo;t think of before?&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Sadly it seems that Light Table&amp;rsquo;s current Python support is limited to allowing reevaluation of individual expressions upon request. Its support for Clojure is better, including an &amp;ldquo;instarepl&amp;rdquo; which evaluates all expressions as they are typed and displays the results of all intermediate variables and data flows.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/08/13/fixing-a-function-at-runtime-without-restarting-the-program</id>
   <title>Fixing a function at runtime without restarting the program</title>
   <published>2013-08-13T00:00:00+00:00</published>
   <updated>2013-08-13T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/08/13/fixing-a-function-at-runtime-without-restarting-the-program/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;This weekend I spent some time writing programs that scrape the contents of various websites to extract information. One challenge when doing this is that webpages are a mess and the functions I wrote to parse the webpages would frequently crash due to some kind of unexpected input. So I decided I wanted a way to fix these functions at runtime without needing to restart the entire program.&lt;/p&gt;

&lt;p&gt;So after hacking around with the Python debugger and employing some magic, I created a new function decorator called &lt;code&gt;@retriable&lt;/code&gt;. This decorator drops into the debugger if a decorated function raises an exception, allowing you to inspect what caused the crash. Then you could fix the function in the source file and exit the debugger. Afterwards the function would be reloaded and called again with the same input as before, all without interrupting the overall program.&lt;/p&gt;

&lt;h2&gt;Demo&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s illustrate the decorator&amp;rsquo;s use with the following program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# flakey.py

from retriable import retriable

@retriable
def identity(input):
    if input in [5, 7]:
        raise ValueError('Could not understand input: %d' % input)
    return input
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This contrived function is intended to return its input unmodified, but fails with certain inputs.&lt;/p&gt;

&lt;p&gt;The above function will be exercised with the following main program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# main.py

import flakey

for i in xrange(1, 10 + 1):
    print flakey.identity(i)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s try to run the main program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python main.py
1
2
3
4
&amp;gt; /Users/davidf/Projects/scrape-tools/flakey.py(7)identity()
-&amp;gt; raise ValueError('Could not understand input: %d' % input)
(Pdb) 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Uh oh. The function crashed. Let&amp;rsquo;s see what the input was:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(Pdb) input
5
(Pdb) 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay. Examining the function in &lt;code&gt;flakey.py&lt;/code&gt; we see the if-statement that&amp;rsquo;s causing &lt;code&gt;5&lt;/code&gt; to fail. So we change it to read &lt;code&gt;if input in [7]:&lt;/code&gt; to fix it and resave the file.&lt;/p&gt;

&lt;p&gt;Having made our fix, we tell the debugger to exit, and instruct the next prompt to retry the function.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(Pdb) quit
[R]etry after reload, Rais[E], or [Q]uit? [R] r
5
6
&amp;gt; /Users/davidf/Projects/scrape-tools/flakey.py(7)identity()
-&amp;gt; raise ValueError('Could not understand input: %d' % input)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the function handled &lt;code&gt;5&lt;/code&gt; but crashed on input &lt;code&gt;7&lt;/code&gt;. Again we fix the function by removing the condition completely, leaving only: &lt;code&gt;def identity(input): return input&lt;/code&gt;. Resaving and retrying the function gives:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(Pdb) quit
[R]etry after reload, Rais[E], or [Q]uit? [R] r
7
8
9
10
$ 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice. The program completed without interruption and we were able to fix the &lt;code&gt;identity&lt;/code&gt; function along the way.&lt;/p&gt;

&lt;p&gt;Although this example is contrived you could imagine saving a lot of time if the function to be fixed was moderately expensive and needed to be invoked hundreds of times by the original program instead of just a handful of times. In such cases restarting the entire program is rather expensive.&lt;/p&gt;

&lt;h2&gt;The &lt;code&gt;@retriable&lt;/code&gt; decorator&lt;/h2&gt;

&lt;p&gt;So, without further ago, here the &lt;code&gt;@retriable&lt;/code&gt; decorator:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# retriable.py

import pdb
import sys

def retriable(func):
    &quot;&quot;&quot;
    Marks a moderately expensive function that needs to support being
    debugged and fixed at runtime without interrupting the calling program.

    A function marked with this decorator that crashes by raising an exception
    will cause the Python debugger to be started at the point where the
    exception was thrown. When the debugger exits, the user will be given the
    option to reload the function and reinvoke it with the original input.

    This decorator only works for top-level functions in a module that are
    idempotent, meaning that they return the same result regardless of how many
    times they are invoked with the same input.

    Functions marked in this way should only be invoked from external modules
    via its module object. So instead of `from module import retriable_function`
    use `import module` and invoke the function using
    `module.retriable_function(...)`.

    NOTE: When a decorated function (and its containing module) is reloaded,
          any callers on the stack that reside within the reloaded module will
          continue to execute the pre-reloaded version of themselves. Therefore
          it is less confusing if functions marked as @retriable are not
          directly or indirectly invoked by methods in the same module.

    Author: David Foster (dafoster.net)
    License: MIT
    Tested On: CPython 2.7
    &quot;&quot;&quot;

    if sys._getframe().f_back.f_code.co_name != '&amp;lt;module&amp;gt;':
        raise AssertionError(
            'The @retriable decorator can only be safely applied to ' +
            'top-level functions within a module.')

    module = sys.modules[func.__module__]
    func_name = func.__name__

    def decorated_func(*args, **kwargs):
        while True:
            try:
                return func(*args, **kwargs)
            except:
                # Start debugger at point where exception was raised
                tb = sys.exc_info()[2]
                pdb.post_mortem(tb)

                # Prompt user whether to try again or not
                while True:
                    choice = raw_input(
                        '[R]etry after reload, Rais[E], or [Q]uit? [R] ')
                    if len(choice) == 0 or choice[0].lower() == 'r':
                        # Retry after reload
                        break
                    elif choice[0].lower() == 'e':
                        # Raise
                        raise
                    elif choice[0].lower() == 'q':
                        # Quit
                        sys.exit(1)
                    else:
                        # Not understood... ask again
                        continue

                # Retry after reload, recursively
                reload(module)
                return getattr(module, func_name)(*args, **kwargs)
    return decorated_func
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some limitations and caveats about this decorator&amp;rsquo;s use are described in its docstring.&lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/07/27/sending-email-from-command-line-scripts</id>
   <title>Sending email from command line scripts</title>
   <published>2013-07-27T00:00:00+00:00</published>
   <updated>2013-07-27T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Productivity"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/07/27/sending-email-from-command-line-scripts/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;This weekend I open-sourced a script called &lt;a href=&quot;https://github.com/davidfstr/notifymail&quot;&gt;notifymail&lt;/a&gt; which I have been using for the past few years to send myself emails from automated scripts, particularly Python scripts.&lt;/p&gt;

&lt;p&gt;It is very easy to configure &lt;code&gt;notifymail&lt;/code&gt; for the first time:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ pip install notifymail
$ notifymail.py --setup
SMTP Server Hostname: smtp.gmail.com
SMTP Server Port [465]: 587
SMTP Server Uses TLS (y/n) [n]: yes
SMTP Username: robot@gmail.com
SMTP Password: ********
From Address [robot@gmail.com]: robot@gmail.com
From Name (optional) []: notifymail
To Address: admin@example.com

Verifying connection to SMTP server... OK
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Check your mail provider&amp;rsquo;s documentation to get the SMTP settings mentioned above. For example I made an internet search for &amp;ldquo;gmail SMTP settings&amp;rdquo; to find &lt;a href=&quot;https://support.google.com/mail/troubleshooter/1668960?hl=en#ts=1665119,1665162&quot;&gt;Gmail&amp;rsquo;s SMTP settings&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gmail SMTP Server:&lt;/strong&gt; smtp.gmail.com&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gmail SMTP Port:&lt;/strong&gt; 587 (for TLS)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gmail SMTP Uses TLS?&lt;/strong&gt; yes&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Once you have &lt;code&gt;notifymail&lt;/code&gt; installed, you can send an email to yourself in a Python script with as little code as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import notifymail
notifymail.send('Subject', 'Hello World', from_name='greeting_script')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or you can invoke &lt;code&gt;notifymail&lt;/code&gt; from the command line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ echo &quot;Hello World&quot; | notifymail.py -s &quot;Subject&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Full documentation is available on the &lt;a href=&quot;https://github.com/davidfstr/notifymail#readme&quot;&gt;notifymail project page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Hasn&amp;rsquo;t this been done before?&lt;/h2&gt;

&lt;p&gt;I reinvented my own wheel to send email principally because of the poor documentation of other alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;mail&lt;/code&gt; and &lt;code&gt;postfix&lt;/code&gt; were so complicated I couldn&amp;rsquo;t figure out how to set them up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ssmtp&lt;/code&gt; didn&amp;rsquo;t work after I tried to configure it and there was no good documentation to help me debug why it wasn&amp;rsquo;t working.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For reference, here&amp;rsquo;s &lt;a href=&quot;http://unix.stackexchange.com/questions/36982/can-i-set-up-system-mail-to-use-an-external-smtp-server&quot;&gt;some information for setting up those alternatives&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Fun things to do with &lt;code&gt;notifymail&lt;/code&gt;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I have a script called &lt;code&gt;heartbeat&lt;/code&gt; that periodically attempts to connect to all of my servers via SSH. If it cannot connect to a server it sends me an email with &lt;code&gt;notifymail&lt;/code&gt;. If it cannot access email it displays a sticky Growl notification locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have another script called &lt;code&gt;meetupfilter&lt;/code&gt; that tracks incoming &amp;ldquo;New Meetup Group&amp;rdquo; emails from &lt;a href=&quot;http://www.meetup.com/&quot;&gt;Meetup&lt;/a&gt;. It waits until all such announced groups have at least 3 events on their calendar before sending me a notification at my personal email with &lt;code&gt;notifymail&lt;/code&gt;. That way I don&amp;rsquo;t hear about Meetup groups that appear but then fizzle out immediately, which is a surprising number. I may open-source this script eventually if I &lt;a href=&quot;/contact&quot;&gt;hear there is interest&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/07/13/error-handling</id>
   <title>Error Handling</title>
   <published>2013-07-13T00:00:00+00:00</published>
   <updated>2013-07-13T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/07/13/error-handling/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Most of the time programs operate happily inside their &lt;em&gt;main scenario&lt;/em&gt;. Occasionally they need to cope with unusual circumstances, such as being no longer able to read data from the network because the user has turned off their WiFi. The process by which a program responds to an error is called &lt;em&gt;error handling&lt;/em&gt;.&lt;/p&gt;

&lt;!--
In many domains error handling is not treated very seriously as errors may be uncommon or the cost of improper handling may be low. In other domains such as telecom or real-time systems, all error cases need to be considered carefully.
--&gt;




&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#behaviors-upon-failure&quot;&gt;Behaviors Upon Failure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#reporting-errors&quot;&gt;Reporting Errors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#error-seriousness&quot;&gt;Error Seriousness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#guarantees-after-failure&quot;&gt;Guarantees after Failure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#failing-fast&quot;&gt;Failing Fast (and Error Locality)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#assert-vs-if&quot;&gt;assert vs. if&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#implementation-considerations-for-exceptions&quot;&gt;Implementation Considerations for Exceptions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#exceptions-are-api&quot;&gt;Exceptions are API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#designing-exception-hierarchies&quot;&gt;Designing Exception Hierarchies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#designing-error-messages&quot;&gt;Designing Error Messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#translating-exceptions-during-handling&quot;&gt;Translating Exceptions During Handling&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#wrapping-low-level-exceptions-in-high-level-exceptions&quot;&gt;Wrapping Low-Level Exceptions in High-Level Exceptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#wrapping-error-codes-in-exceptions&quot;&gt;Wrapping Error Codes in Exceptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#promoting-error-sentinels-to-exceptions&quot;&gt;Promoting Error Sentinels to Exceptions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#avoid-using-error-codes-in-generic-exceptions&quot;&gt;Avoid Using Error Codes in Generic Exceptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#avoid-using-exceptions-for-flow-control&quot;&gt;Avoid Using Exceptions for Flow Control&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#using-exceptions-for-thread-termination&quot;&gt;Using Exceptions for Thread Termination&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;behaviors-upon-failure&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Behaviors Upon Failure&lt;/h2&gt;

&lt;p&gt;At the time an error occurs in a function there are a few things it can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Delegate to its caller&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Typically a function doesn&amp;rsquo;t have enough information to decide how to handle the error itself. In such a case the error is reported to the calling function, which is typically higher-level and has more context.&lt;/li&gt;
&lt;li&gt;For example if an I/O error occurs while parsing data from a file, the parser will typically just report the I/O error to the code that invoked the parser. The parser itself only knows how to parse things and not what should be done in the case of an I/O error.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The particular error handling strategy of a function reporting an error to its caller is so common that many programming languages provide special mechanisms to support it, particularly in the form of &lt;em&gt;exceptions&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Display the error to the user and continue&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is a common pattern for routine errors in interactive programs.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For example a web browser that cannot access a particular webpage will display an error page explaining why the page could not be accessed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Display the error to the user and exit&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is a common pattern for unexpected errors in contexts where total program failure is deemed acceptable.&lt;/li&gt;
&lt;li&gt;In languages that use exceptions, any unhandled exceptions that bubble out of the main function or to the initial function in a thread will terminate the program or the thread. Programs can avoid this fate by adding a top-level exception handler that takes alternate action.&lt;/li&gt;
&lt;li&gt;Examples:

&lt;ul&gt;
&lt;li&gt;In PHP it is an idiom to use the &lt;code&gt;die()&lt;/code&gt; function upon the failure of many operations:

&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;$connection = mysql_connect('localhost', 'dbuser', 'password') or die('Could not connect to MySQL server.');
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Linux kernel makes great use of the &lt;code&gt;panic()&lt;/code&gt; function when it gets into a bad state, stopping the entire operation of the computer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log the error and continue&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is a common pattern for non-interactive programs and programs that need to keep running continuously, such as web servers.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Naturally there needs to be somebody who goes through the log occasionally to look for problems if this error handling strategy is used.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignore the error implicitly and continue blindly&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is almost always done out of laziness.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In C, this just means ignoring the result of a function that returns an error code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignore the error explicitly and continue boldly&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is usually done out of laziness.&lt;/li&gt;
&lt;li&gt;One legitimate case when this is done is ignoring I/O errors when closing a resource during cleanup, since there isn&amp;rsquo;t anything sensible that can be done at that point. A Java example:

&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;r = new Resource();
try {
    ...
} finally {
    try {
        r.close();
    } catch (IOException e) {
        // ignore
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Less common handling strategies include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt the user to decide what to do&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attempt recovery and retry (or resume) the original operation&lt;/strong&gt;, perhaps with different inputs&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;reporting-errors&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Reporting Errors&lt;/h2&gt;

&lt;p&gt;When a function wants to report an error, it has to pass information about the error to its caller. There are a few ways that error information can be encapsulated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Error Codes&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;When a function is designed to report errors using error codes, it is declared to return an integer or other integer alias (ex: &lt;code&gt;OSErr&lt;/code&gt;). Upon success the function returns 0 (or &lt;code&gt;noErr&lt;/code&gt;). Upon failure the function returns some other value that describes the type of error encountered. Should the function need to return other values upon success it must declare &lt;em&gt;out parameters&lt;/em&gt; to pass them back to the caller.&lt;/li&gt;
&lt;li&gt;Error codes have several disadvantages that make their use uncommon in modern high level languages:

&lt;ul&gt;
&lt;li&gt;An error code only describes the type of error encountered, but not any additional contextual information that would be useful in handling the error. Typically only the function that is one hop away from the error site has enough additional context to actually handle the error nicely.

&lt;ul&gt;
&lt;li&gt;For example if you try to open a nonexistent file on classic Mac OS, you&amp;rsquo;ll get back the error code &lt;code&gt;fnfErr&lt;/code&gt; which indicates that the specified file was not found. Note however that this error code alone doesn&amp;rsquo;t include information about &lt;em&gt;which&lt;/em&gt; file couldn&amp;rsquo;t be found, which is necessary context to display a meaningful error message.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A function that uses error codes relies on its caller to check whether it returns an error. Lazy callers might not actually check, causing any reported errors to be ignored silently.

&lt;ul&gt;
&lt;li&gt;For example I have never seen a C program actually check the result of &lt;code&gt;printf()&lt;/code&gt;, even though it can return an error code upon I/O error. This behavior is reasonable in this case because there isn&amp;rsquo;t much a program can do to alert the user if it can&amp;rsquo;t print to the screen.&lt;/li&gt;
&lt;li&gt;More problematic are C programs that fail to check the result of &lt;code&gt;malloc()&lt;/code&gt; for &lt;code&gt;NULL&lt;/code&gt; when allocating objects. Such programs will crash when &lt;code&gt;malloc&lt;/code&gt; returns &lt;code&gt;NULL&lt;/code&gt; during an out-of-memory condition and the caller tries to manipulate it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When an error code occupies the return value of a function, that return value can&amp;rsquo;t be used for &amp;ldquo;normal&amp;rdquo; function output. This typically means that multiple functions returning error codes cannot be chained together on the same line, increasing verbosity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The one advantage of error codes is that they are very fast to create and return, improving performance in fragments of code that experience a large number of errors. However this performance-over-usability tradeoff is almost never worth it in modern programs.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;These days error codes are only used commonly in programming languages like C that don&amp;rsquo;t support the use of exceptions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Sentinels&lt;/strong&gt; (such as &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;-1&lt;/code&gt;, or &lt;code&gt;0&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;A function that reports errors using error sentinels uses its return value to return the normal output of the function most of the time. However when an error occurs, a special invalid&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; value (a &lt;em&gt;sentinel&lt;/em&gt;) is returned instead.

&lt;ul&gt;
&lt;li&gt;For example if you &lt;code&gt;read()&lt;/code&gt; from an &lt;code&gt;InputStream&lt;/code&gt; in Java, usually the resultant byte value is returned. But if the end-of-file is reached, the special value of &lt;code&gt;-1&lt;/code&gt; is returned instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Error sentinels suffer from the same disadvantages as error codes. And they have the same performance advantage.&lt;/li&gt;
&lt;li&gt;Unfortunately the use of error sentinels, especially &lt;code&gt;null&lt;/code&gt;, remains common in many modern programs despite their disadvantages. Even in cases where a &lt;a href=&quot;https://en.wikipedia.org/wiki/Null_Object_pattern&quot;&gt;Null Object&lt;/a&gt; could be used to better effect.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some statically typed languages like Haskell and SML explicitly represent the potential of a sentinel being returned using a datatype such as &lt;code&gt;Maybe&lt;/code&gt; or &lt;code&gt;Option&lt;/code&gt;. Typically this is done so that the compiler can automatically flag callers that aren&amp;rsquo;t checking for sentinels properly, eliminating their largest disadvantage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exceptions&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;em&gt;exception&lt;/em&gt; is an object that encapsulates information about an error. This includes not only the type of error but also additional contextual information that can be used to generate a reasonable error message and assist in debugging by an end-user or developer.

&lt;ul&gt;
&lt;li&gt;Exceptions also typically include a &lt;em&gt;stack trace&lt;/em&gt; which can be used to pinpoint the location in the program where the error occurred originally, which is valuable for debugging.&lt;/li&gt;
&lt;li&gt;Some languages like Java and Python provide &lt;em&gt;exception chaining&lt;/em&gt; (or &lt;em&gt;wrapping&lt;/em&gt;), which is special support for higher-level exceptions to reference any lower-level exceptions that caused the higher-level exception to occur.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A function that uses exceptions for error reporting can &lt;em&gt;throw&lt;/em&gt; (or &lt;em&gt;raise&lt;/em&gt;) an exception when an error occurs. When this happens the runtime looks for an enclosing &lt;em&gt;exception handler&lt;/em&gt; that knows how to deal with the exception. If it finds a handler the handler is run. If no such handler is found the function terminates and the same exception is rethrown at the point in the caller function where the throwing function was called. Should there be no caller, such as in the case of the main function or the initial function of a thread, the program or thread terminates.&lt;/li&gt;
&lt;li&gt;Exceptions are the preferred method for error handling in most modern languages. They have the principal advantages of preserving detailed information about the error that occurred and being difficult to accidentally ignore.&lt;/li&gt;
&lt;li&gt;One disadvantage of using exceptions is that they are relatively expensive to create and throw which can be a problem if the related error is relatively common, such as attempting to read past the end of a file. They also typically require special language support for throwing them, which rules out their use in simpler languages like C.&lt;/li&gt;
&lt;li&gt;Some languages such as Java additionally have the notion of a &lt;em&gt;checked exception&lt;/em&gt;. When a function throws a checked exception, it is required to declare the type of the exception in its signature. When a caller tries to invoke a function that declares a checked exception in its signature, the compiler enforces that the caller actually handles the exception - either with an exception handler or by delegating to a higher-level function.

&lt;ul&gt;
&lt;li&gt;It is challenging to design APIs that use checked exceptions since they propagate virally through function declarations. I will probably write a future article that specifically deals with using checked exceptions effectively.&lt;/li&gt;
&lt;li&gt;Some statically typed languages like Haskell implement the semantics of checked exceptions using a datatype such as &lt;code&gt;Either&lt;/code&gt;. Compilers in such languages enforce that callers explicitly unpack the &lt;code&gt;Either&lt;/code&gt; value and handle any contained exception object explicitly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exceptions should be used for most error reporting needs.&lt;/li&gt;
&lt;li&gt;Error sentinels should be used to report &lt;a href=&quot;#common-error&quot;&gt;common errors&lt;/a&gt; where the performance penalty of exceptions is too much.&lt;/li&gt;
&lt;li&gt;Error codes should be avoided entirely unless the programming language does not support exceptions, in which case error codes should be used instead.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;error-seriousness&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Error Seriousness&lt;/h2&gt;

&lt;p&gt;Often the seriousness of an error is related to how it is handled. Generally speaking, errors are either:
&lt;a id=&quot;common-error&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Common&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;For example reading past the end of a file falls into this category, as it will always happen (once) whenever a program attempts to read an entire file into memory.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Very few errors fall into this category.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expected&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;These errors are likely to occur in normal operation, but not commonly.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I/O errors related to reading from a file or from a network socket are an example.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unexpected&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Unexpected errors are ones for which the programmer did not plan any explicit handling.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This includes dividing by zero, dereferencing a null pointer, attempting to access an object off the end of an array, reading from a file that was closed, and other &amp;ldquo;programmer errors&amp;rdquo;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fatal&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Fatal errors are a rare and particularly nasty subset of unexpected errors for which there is no good recovery strategy. Such errors almost always terminate the program when &lt;span class=&quot;nobr&quot;&gt;they occur&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Fatal errors include running out of memory&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, the inability to locate a method or library which the program was linked against, and other nasty conditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;!-- NOTE: This paragraph is (usefully) redundant with the summary in the &quot;Reporting Errors&quot; section above: --&gt;


&lt;p&gt;Common errors are typically reported using error sentinels or error codes for performance reasons. Other error categories are usually reported using exceptions unless the language in use doesn&amp;rsquo;t support exceptions, in which case error codes are used instead.&lt;/p&gt;

&lt;p&gt;The standard libraries of programming languages typically distinguish between expected, unexpected, and fatal errors by using different exception base classes for each. This makes it easy to write exception handlers that can catch all thrown exceptions in a particular category. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Java uses &lt;code&gt;Error&lt;/code&gt; as the base class for fatal errors, &lt;code&gt;RuntimeException&lt;/code&gt; for unexpected errors, and all other subclasses of &lt;code&gt;Exception&lt;/code&gt; for expected errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;C# uses &lt;code&gt;SystemException&lt;/code&gt; (informally) as the base class for unexpected and fatal errors. All other subclasses of &lt;code&gt;Exception&lt;/code&gt; are used for expected errors.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python uses &lt;code&gt;StandardError&lt;/code&gt; (informally) as the base class for unexpected and fatal errors. All other subclasses of &lt;code&gt;Exception&lt;/code&gt; are used for expected errors.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If a language supports checked exceptions, the expected exceptions should generally be marked as checked to force callers to handle them appropriately. Conversely, unexpected and fatal exceptions should &lt;em&gt;not&lt;/em&gt; be marked as checked since this burdens the caller unnecessarily.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;guarantees-after-failure&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Guarantees after Failure&lt;/h2&gt;

&lt;p&gt;When an error occurs in the middle of multi-step function, the function has to make a decision about what kind of state it wants to leave the program in when it returns to its caller. In general a function can leave the program:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;in its original state,&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This usually involves rolling back or reversing any actions performed prior to the error.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Functions that make this guarantee are called &lt;em&gt;atomic&lt;/em&gt; or &lt;em&gt;transactional&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;in a different but valid state,&lt;/strong&gt; or

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If a full rollback is not possible, it is still usually possible to partially rollback to a &lt;span class=&quot;nobr&quot;&gt;valid state&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;in a different and potentially illegal state.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Naive functions may simply return immediately upon error, leaving whatever resources they were using in a bad state.&lt;/li&gt;
&lt;li&gt;This is particularly a problem for programs that use exceptions for error handling, as the default behavior when an exception is thrown is to return immediately, without performing any cleanup.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Any complex fault-tolerant function should document which of these guarantees it makes.&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; If it makes no guarantees at all, the caller may have to assume that whatever resource the function was operating on is in a bad state if the function returns an error.&lt;/p&gt;

&lt;p&gt;Consider the concrete example of a program that copies a comma-separated-value (CSV) file to a new file. This generally involves the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the source CSV file.&lt;/li&gt;
&lt;li&gt;Open the destination file, replacing any previously existing file.&lt;/li&gt;
&lt;li&gt;Loop over each row (or byte) of the source CSV file and write each row to the destination.&lt;/li&gt;
&lt;li&gt;Close the destination file.&lt;/li&gt;
&lt;li&gt;Close the source file.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Here is a naive implementation that makes no guarantees to its caller in the event of an error.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/** Copies the source CSV file to the destination file. */
// (I didn't think about error handling at all.)
public static void copyCsvFile(File sourceFile, File destFile) throws IOException {
    InputStream fileIn = new FileInputStream(sourceFile);
    OutputStream fileOut = new FileOutputStream(destFile);
    int b;
    while ((b = fileIn.read()) != -1) {
        fileOut.write(b);
    }
    fileOut.close();
    fileIn.close();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now imagine what happens if an I/O error occurs in the middle of copying bytes: The &lt;code&gt;write&lt;/code&gt; method will throw an &lt;code&gt;IOException&lt;/code&gt; and since &lt;code&gt;copyCsvFile&lt;/code&gt; has no matching exception handler, the &lt;code&gt;copyCsvFile&lt;/code&gt; function itself will stop and rethrow the &lt;code&gt;IOException&lt;/code&gt;. Notably, the destination file is left with incomplete and invalid CSV contents. And neither the source nor the destination file is closed, leaking those resources from the operating system.&lt;/p&gt;

&lt;p&gt;We can at least avoid leaking resources by adding logic that ensures that resources are always closed when the function completes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/** Copies the source CSV file to the destination file. */
// (No open file handles will be leaked even in the event of an error.)
public static void copyCsvFile(File sourceFile, File destFile) throws IOException {
    InputStream fileIn = new FileInputStream(sourceFile);
    try {
        OutputStream fileOut = new FileOutputStream(destFile);
        try {
            int b;
            while ((b = fileIn.read()) != -1) {
                fileOut.write(b);
            }
            fileOut.flush();
        } finally {
            try {
                fileOut.close();
            } catch (IOException e) {
                // Ignore I/O errors upon close since nothing can be done
            }
        }
    } finally {
        try {
            fileIn.close();
        } catch (IOException e) {
            // Ignore I/O errors upon close since nothing can be done
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This improved function will no longer leak open file handles in the event of an error but it will still leave an invalid destination CSV file.&lt;/p&gt;

&lt;p&gt;If we document the additional guarantee that the function performs an &lt;em&gt;atomic&lt;/em&gt; file copy, we&amp;rsquo;d want to explicitly code the function to delete the destination file in the event that it couldn&amp;rsquo;t be fully copied. Here&amp;rsquo;s an implementation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/** Copies the source CSV file to the destination file atomically. */
public static void copyCsvFile(File sourceFile, File destFile) throws IOException {
    InputStream fileIn = new FileInputStream(sourceFile);
    try {
        OutputStream fileOut = new FileOutputStream(destFile);
        boolean finishedCopying = false;
        try {
            int b;
            while ((b = fileIn.read()) != -1) {
                fileOut.write(b);
            }
            fileOut.flush();
            finishedCopying = true;
        } finally {
            try {
                fileOut.close();
            } catch (IOException e) {
                // Ignore I/O errors upon close since nothing can be done
            }

            if (!finishedCopying) {
                boolean deleteSuccess = destFile.delete();
                // If the delete fails then the rollback failed.
                // Since there's nothing that can be done in that case,
                // we ignore deletion failures.
            }
        }
    } finally {
        try {
            fileIn.close();
        } catch (IOException e) {
            // Ignore I/O errors upon close since nothing can be done
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we wanted to get even more fancy we could document instead that the function guarantees that it will copy as much of the source CSV file to the destination CSV file, leaving the longest valid destination CSV file even in the case of an error. In particular if the entire file cannot be copied, the function will copy as many complete lines from the source CSV file as possible, stripping off any incompletely written lines.&lt;/p&gt;

&lt;p&gt;This is actually relatively difficult to implement correctly in Java while still &lt;a href=&quot;/articles/2013/06/01/handling-text-correctly/&quot;&gt;handling characters correctly&lt;/a&gt; and preserving end-of-line sequences, so here&amp;rsquo;s a Python 2 implementation instead:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def copy_csv_file(source_filepath, dest_filepath):
    &quot;&quot;&quot;
    Copies the source CSV file to the destination file.

    If an error occurs while copying, as many rows as possible are copied,
    leaving a valid destination CSV file.
    &quot;&quot;&quot;
    with open(source_filepath, 'rb') as file_in:
        offset_to_last_line_written = 0
        finished_copying = False
        file_out = open(dest_filepath, 'wb')
        try:
            while True:
                cur_line_bytes = file_in.readline()
                file_out.write(cur_line_bytes)
                offset_to_last_line_written = file_out.tell()
            file_out.flush()
            finished_copying = True
        finally:
            truncated_successfully = False
            if not finished_copying:
                try:
                    file_out.truncate(offset_to_last_line_written)
                    truncated_successfully = True
                except IOError:
                    # Unable to truncate. Will try to delete the file instead...
                    pass

            try:
                file_out.close()
            finally:
                if not finished_copying and not truncated_successfully:
                    try:
                        os.remove(dest_filepath)
                    except IOError:
                        # Unable to truncate or remove the destination file.
                        # Nothing else can be done.
                        pass
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Actually the preceding implementation isn&amp;rsquo;t correct in the presence of output stream buffering (unless it is line-buffered), since it could be the case that the &lt;code&gt;offset_to_last_line_written&lt;/code&gt; points to the end of a line that in fact has not been written to disk but is rather in the output buffer. A correct and performant implementation that additionally handles that case is left as a &lt;span class=&quot;nobr&quot;&gt;(non-trivial)&lt;/span&gt; exercise for the reader.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;failing-fast&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Failing Fast &lt;small&gt;and Error Locality&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;Errors are easiest to handle when they are signaled at the exact point where a problem first occurred, or as close to it as possible. Thus functions should try to &lt;em&gt;fail fast&lt;/em&gt; whenever possible.&lt;/p&gt;

&lt;p&gt;It is a good idea for functions to check their inputs (especially their arguments) immediately upon invocation to see whether they conform to the expected format. This provides early warning of state corruption that could get introduced into the derived output of the function.&lt;/p&gt;

&lt;p&gt;In addition if there are points where a function can make a non-trivial assertion about its current state, and this assertion is at risk of breaking due to modifications by maintainers, it should make an explicit check that the assertion is true.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;assert-vs-if&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;assert&lt;/code&gt; vs. &lt;code&gt;if&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;When checking assertions, a function can always use the humble &lt;code&gt;if&lt;/code&gt; statement:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public class Registry {
    private Map&amp;lt;String, Object&amp;gt; items = new LinkedHashMap&amp;lt;String, Object&amp;gt;();

    public void register(String id, Object item) {
        if (id == null)
            throw new IllegalArgumentException(
                &quot;Cannot register an item with a null ID.&quot;);
        if (item == null)
            throw new IllegalArgumentException(
                &quot;Cannot register a null item with ID \&quot;&quot; + id + &quot;\&quot;.&quot;);

        if (items.containsKey(id))
            throw new IllegalStateException(
                &quot;Already have an item registered with the ID \&quot;&quot; + id + &quot;\&quot;.&quot;);
        items.put(id, item);
    }

    // (... more methods ...)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However there is also an &lt;code&gt;assert&lt;/code&gt; statement in many languages. The &lt;code&gt;assert&lt;/code&gt; statement typically differs from &lt;code&gt;if&lt;/code&gt; in that it can be compiled-out of the program automatically if desired, for a modest performance boost at the expense of safety. Therefore &lt;code&gt;assert&lt;/code&gt; should typically only be used in performance-critical code (that has been verified as such by a profiler).&lt;/p&gt;

&lt;p&gt;In practice I almost never use &lt;code&gt;assert&lt;/code&gt;, preferring to rely on &lt;code&gt;if&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;implementation-considerations-for-exceptions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Implementation Considerations for Exceptions&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;exceptions-are-api&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Exceptions are API&lt;/h3&gt;

&lt;p&gt;Expected exceptions&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; are part of a function&amp;rsquo;s API. Consequently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Expected exceptions should be given the same coverage in a function&amp;rsquo;s documentation as its parameters or return type. Remembering to document expected exceptions is particularly important when writing API documentation for languages lacking checked exceptions (i.e. everything other than Java, including C#).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Callers may depend on the expected exceptions in the function&amp;rsquo;s API documentation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;A function cannot remove or change the exceptions it throws without breaking callers that have been coded to expect the old set of exceptions. And new exceptions that are added will not be expected by existing callers.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;designing-exception-hierarchies&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Designing Exception Hierarchies&lt;/h3&gt;

&lt;p&gt;It is generally a good idea have a separate exception type for each specific type of error that a caller might want to handle distinctly. That way a caller can easily write an exception handler that catches a specific exception of interest. For example &lt;code&gt;FileNotFoundException&lt;/code&gt; is likely to be treated distinctly from a generic &lt;code&gt;IOException&lt;/code&gt;, so it is given a separate exception type (that inherits from the generic &lt;code&gt;IOException&lt;/code&gt; class).&lt;/p&gt;

&lt;p&gt;Errors that are not likely to be handled distinctly by the caller can just reuse a generic exception class directly. For example a piece of code that detected a &amp;ldquo;bad media&amp;rdquo; error when reading from a disk could just throw a plain &lt;code&gt;IOException&lt;/code&gt; with a message instead of creating a special subclass. However note that by doing this you provide no API for any caller that &lt;em&gt;does&lt;/em&gt; in fact want to catch this kind of exception.&lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;designing-error-messages&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Designing Error Messages&lt;/h3&gt;

&lt;p&gt;An error message typically accompanies an exception, and it is this message that is typically presented verbatim to the user if high-level code doesn&amp;rsquo;t recognize the exception type itself. Therefore it is important that the message be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;well-formatted&lt;/strong&gt;,

&lt;ul&gt;
&lt;li&gt;Therefore basic grammar rules apply, such as beginning sentences with a capital letter and ending them with a period.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A surprising number of real-world exception messages don&amp;rsquo;t even meet this low bar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;understandable by the user&lt;/strong&gt;,

&lt;ul&gt;
&lt;li&gt;This is a tricky requirement because the point where an exception is generated may not know the kind of user that will eventually receive the exception, particularly if it is a low-level error that is deeply buried or if the error occurs in a widely-used utility function.&lt;/li&gt;
&lt;li&gt;In general &lt;em&gt;expected&lt;/em&gt; errors are likely to reach a normal non-programmer end-user, so they should be written with that audience in mind.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By constrast &lt;em&gt;unexpected&lt;/em&gt; and &lt;em&gt;fatal&lt;/em&gt; errors are typically programmer errors and only likely to be seen by other developers when developing a program. Therefore they should be written with the developer in mind.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;specific&lt;/strong&gt;, and

&lt;ul&gt;
&lt;li&gt;An error message without sufficient contextual information cannot be easily corrected by the person that receives it. Messages should contain enough information for the user to easily locate the problem and fix it themselves.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For example a error encountered while parsing a text file should include information about the &lt;em&gt;location&lt;/em&gt; of the parse error, so that the user can find the problem in the original document. Any good compiler will give you at least a line number when it encounters a syntax error and may even provide a specific column number as well.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;in the correct spoken language&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;In particular if the user&amp;rsquo;s current locale is non-English (such as German), a German message should be presented if possible, not a default English one.&lt;/li&gt;
&lt;li&gt;Programs that are only intended to be used in a single locale can ignore this guideline and naively emit messages in the expected locale&amp;rsquo;s language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;translating-exceptions-during-handling&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Translating Exceptions During Handling&lt;/h3&gt;

&lt;p&gt;&lt;a id=&quot;wrapping-low-level-exceptions-in-high-level-exceptions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Wrapping Low-Level Exceptions in High-Level Exceptions&lt;/h4&gt;

&lt;p&gt;It is common for a single system to have a single high-level exception type that is thrown by most of its functions. For example a parser&amp;rsquo;s functions may all throw the high-level &lt;code&gt;ParseException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However the implementation of such a system may delegate to other systems that use a different set of exceptions. In the case of a parser, it typically has to read the characters it is parsing from an I/O stream, which may throw a low-level &lt;code&gt;IOException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, top-level parser functions have a few options in reporting the underlying &lt;code&gt;IOException&lt;/code&gt; as a possible failure case to its caller:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Expose&lt;/strong&gt; - The top-level function declares that it throws both &lt;code&gt;ParseException&lt;/code&gt; and &lt;code&gt;IOException&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;However this exposes the implementation detail that the parsing system relies on the I/O system and forces the caller to deal with the low-level &lt;code&gt;IOException&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Therefore this is not generally recommended for top-level functions, although it may be used by internal functions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wrap&lt;/strong&gt; - The top-level function intercepts &lt;code&gt;IOException&lt;/code&gt;s and translates them to a generic &lt;code&gt;ParseException&lt;/code&gt; that wraps the original &lt;code&gt;IOException&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;This allows the top-level parsing functions to present the simpler exception API of just throwing a &lt;code&gt;ParseException&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Callers of the parser remain able to intercept and extract the underlying &lt;code&gt;IOException&lt;/code&gt; if they wish.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map&lt;/strong&gt; - The top-level function intercepts &lt;code&gt;IOException&lt;/code&gt;s and maps them to a special subclass of &lt;code&gt;ParseException&lt;/code&gt; (like &lt;code&gt;ParseIOException&lt;/code&gt;), optionally wrapping the original &lt;code&gt;IOException&lt;/code&gt; for further inspection by the caller.

&lt;ul&gt;
&lt;li&gt;This is similar to the &amp;ldquo;wrapping&amp;rdquo; approach, but makes it even easier for the caller to catch the underlying exception since it can directly catch the mapped exception (&lt;code&gt;ParseIOException&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Thus this approach is preferable if the underlying failure case is sufficiently important to advertise prominently in the exception API.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In summary, most low-level level exceptions should be wrapped in the generic high-level exception. For &lt;em&gt;prominent&lt;/em&gt; low-level exceptions, they should be mapped to a specific high-level exception subclass.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a Java example of a parser taking the &amp;ldquo;wrapping&amp;rdquo; approach to low-level I/O exceptions.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// The top-level methods of this class all throw ParseException in their API.
public class RuleParser {
    public static Rule parse(InputStream input) throws ParseException {
        try {
            return new RuleParser(input).readRule();
        } catch (IOException e) {
            throw new ParseException(&quot;I/O error while parsing rule.&quot;, e);
        }
    }

    private Rule readRule() throws ParseException, IOException {
        // (...)
    }

    // (...)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a id=&quot;wrapping-error-codes-in-exceptions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Wrapping Error Codes in Exceptions&lt;/h4&gt;

&lt;p&gt;Sometimes a high-level function using exceptions needs to report an error received from a low-level function that uses error codes. In this case the low-level error code needs to be communicated to the caller somehow via an exception.&lt;/p&gt;

&lt;p&gt;Typically the low-level function comes from an overall subsystem of some kind which uses error codes in general for error reporting. In such a case it is typical to define a generic exception to wrap all error codes received from the subsystem. This generic exception should preserve the original error code for inspection by callers, along with whatever extra context may be available from the subsystem, typically just an error message.&lt;/p&gt;

&lt;p&gt;For example Python uses the &lt;code&gt;OSError&lt;/code&gt; exception to wrap error codes received from the underlying C library. It is populated with the error code received from the C &lt;code&gt;errno&lt;/code&gt; global variable and the message received from the C function &lt;code&gt;perror()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now the high-level function may not want to report this kind of low-level subsystem exception directly, in which case the &amp;ldquo;wrap&amp;rdquo; or &amp;ldquo;map&amp;rdquo; technique discussed above in &lt;a href=&quot;#wrapping-low-level-exceptions-in-high-level-exceptions&quot;&gt;&amp;ldquo;Wrapping Low-Level Exceptions in High-Level Exceptions&amp;rdquo;&lt;/a&gt; should be used in addition.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;promoting-error-sentinels-to-exceptions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Promoting Error Sentinels to Exceptions&lt;/h4&gt;

&lt;p&gt;Typically error sentinels are used to report common errors that are intended to be handled immediately by the caller. However if the caller cannot handle the error itself but needs to delegate to its second-order caller, it typically needs to promote the sentinel to an exception.&lt;/p&gt;

&lt;p&gt;As an example, the end-of-stream condition when reading from a stream is generally considered to be a common error in Java. However a function that is parsing a data structure out of a stream does &lt;em&gt;not&lt;/em&gt; expect an end-of-stream when it is in the middle of parsing a structure. Thus the parser wishes to report the end-of-stream condition to its caller as either an expected or unexpected error (depending on context), both of which require an exception.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public class BinaryInputStream extends FilterInputStream {
    public BinaryInputStream(InputStream in) {
        super(in);
    }

    public int readUInt8() throws IOException {
        int b = this.read();
        if (b == -1) {
            throw new EOFException(&quot;Unexpected end of stream.&quot;);
        }
        return b;
    }

    public int readUInt16() throws IOException {
        return
            (readUInt8() &amp;lt;&amp;lt; 8) |
            (readUInt8() &amp;lt;&amp;lt; 0);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the preceding example the &lt;code&gt;-1&lt;/code&gt; error sentinel was promoted to an &lt;code&gt;EOFException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;avoid-using-error-codes-in-generic-exceptions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Avoid Using Error Codes in Generic Exceptions&lt;/h3&gt;

&lt;p&gt;The use of internal error codes within a generic exception class should generally be avoided, since this makes it difficult to handle them. (One exception to this guideline is when using an exception to wrap &lt;em&gt;external&lt;/em&gt; error codes received from another subsystem, as described above in &lt;a href=&quot;#wrapping-error-codes-in-exceptions&quot;&gt;&amp;ldquo;Wrapping External Error Codes in Exceptions&amp;rdquo;&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Consider the following example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// A generic exception that wraps its own set of error codes. DON'T DO THIS.
public class FetchException extends RuntimeException {
    private int code;
    private String text;

    public static final int JOB_NOTREADY = 1;
    public static final int TIMEOUT = 2;
    public static final int AMBIGUOUS_NAME = 3;

    FetchException(int code, String text) {
        super(text);
        this.code = code;
        this.text = text;
    }

    public int getCode() {
        return code;
    }

    public String getText() {
        return text;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you actually wanted to detect the &lt;code&gt;JOB_NOTREADY&lt;/code&gt; case, you&amp;rsquo;d have to write code like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public Job fetchJob(String jobName) {
    for (int triesLeft = MAX_FETCH_ATTEMPTS; triesLeft &amp;gt; 0; triesLeft--) {
        try {
            return service.getJobs().get(jobName);
        } catch (FetchException e) {
            if (e.getCode() == FetchException.JOB_NOTREADY) {
                // Retry again
                continue;
            } else {
                throw e;
            }
        }
    }
    throw new FetchException(TIMEOUT,
        &quot;Job \&quot;&quot; + jobName + &quot;\&quot; was not ready after &quot; +
            MAX_FETCH_ATTEMPTS + &quot; fetch attempts.&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s not pleasant having to put that if-statement in the exception handler. And the throwing of the &lt;code&gt;TIMEOUT&lt;/code&gt;-coded &lt;code&gt;FetchException&lt;/code&gt; couldn&amp;rsquo;t save contextual information like the &lt;code&gt;jobName&lt;/code&gt; and &lt;code&gt;MAX_FETCH_ATTEMPTS&lt;/code&gt; in a machine-readable field since the generic &lt;code&gt;FetchException&lt;/code&gt; didn&amp;rsquo;t have fields that were specific to the &lt;code&gt;TIMEOUT&lt;/code&gt; code.&lt;/p&gt;

&lt;p&gt;A better solution would be to use specific subclasses of &lt;code&gt;FetchException&lt;/code&gt; instead:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public class FetchException extends RuntimeException { ... }

public class JobNotReadyException extends FetchException { ... }

public class FetchTimeoutException extends FetchException {
    private String jobName;
    private int numFetchAttempts;

    FetchTimeoutException(String jobName, int numFetchAttempts) {
        super(&quot;Job \&quot;&quot; + jobName + &quot;\&quot; was not ready after &quot; +
            MAX_FETCH_ATTEMPTS + &quot; fetch attempts.&quot;);
        this.jobName = jobName;
        this.numFetchAttempts = numFetchAttempts;
    }

    // (... Accessors for jobName and numFetchAttempts ...)
}

public class AmbiguousNameException extends FetchException { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then the code could be simplified to just read:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public Job fetchJob(String jobName) {
    for (int triesLeft = MAX_FETCH_ATTEMPTS; triesLeft &amp;gt; 0; triesLeft--) {
        try {
            return service.getJobs().get(jobName);
        } catch (JobNotReadyException e) {
            // Retry again
            continue;
        }
    }
    throw new FetchTimeoutException(jobName, MAX_FETCH_ATTEMPTS);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a id=&quot;avoid-using-exceptions-for-flow-control&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Avoid Using Exceptions for Flow Control&lt;/h3&gt;

&lt;p&gt;Sometimes programs report &lt;em&gt;common&lt;/em&gt; errors in the form of an exception instead of using a more appropriate mechanism such as an error sentinel. This is inefficient since throwing exceptions is slow in the common case. And it is awkward for the caller who must have an explicit exception handler around every invocation to deal with the common case. Don&amp;rsquo;t do it.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;using-exceptions-for-thread-termination&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Using Exceptions for Thread Termination&lt;/h4&gt;

&lt;p&gt;However one case where exceptions are useful as a means of flow control is to force (or recommend) that a thread terminate. Such exceptions are classified as fatal errors so that most exception handlers ignore them.&lt;/p&gt;

&lt;p&gt;For example Java uses the &lt;code&gt;ThreadDeath&lt;/code&gt; exception (a subclass of the fatal &lt;code&gt;Error&lt;/code&gt;) to terminate a thread. And Python uses the &lt;code&gt;KeyboardInterrupt&lt;/code&gt; exception (a subclass of the fatal &lt;code&gt;BaseException&lt;/code&gt;) to kill the main thread when the user presses Control-C.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;summary&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;Error handling is hard. But you&amp;rsquo;ll provide a better experience by properly handling and communicating errors back the user.&lt;/p&gt;

&lt;p&gt;Don&amp;rsquo;t be that guy who provides useless generic error messages:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2013/generic_ie_error.png&quot; height=&quot;353&quot; width=&quot;725&quot; alt=&quot;Awful error message from Internet Explorer 9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(I doubt even the program itself knows what went wrong.)&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/11/22/error-handling-styles/&quot;&gt;Error handling styles in programming&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Summarizes the most prominent strategies for handling runtime errors.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2016/05/17/abandonment-vs-unchecked-exceptions-for-error-handling/&quot;&gt;Abandonment vs. Unchecked Exceptions for Error Handling&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes abandonment, an uncommon error-handling style.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Series
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        This article is part of the &lt;a href=&quot;/articles/2013/05/11/book-outline/&quot;&gt;Programming for Perfectionists&lt;/a&gt; series.
    &lt;/p&gt;
&lt;/div&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Flawed functions that return sentinel values that are actually &lt;em&gt;valid&lt;/em&gt; place extra onus on the caller to perform additional checks to determine whether an error actually occurred. For example PHP&amp;rsquo;s &lt;a href=&quot;http://php.net/manual/en/function.stream-get-contents.php&quot;&gt;&lt;code&gt;stream_get_contents&lt;/code&gt;&lt;/a&gt; function can return &lt;code&gt;''&lt;/code&gt; or &lt;code&gt;FALSE&lt;/code&gt; upon failure. But it can also return &lt;code&gt;''&lt;/code&gt; upon success. See my insane &lt;a href=&quot;https://github.com/splunk/splunk-sdk-php/blob/master/Splunk/Util.php&quot;&gt;workaround&lt;/a&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Most programs treat out-of-memory errors as fatal, although there are a few hardened programs like SQLite that treat out-of-memory as an &lt;em&gt;expected&lt;/em&gt; error.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;The C# exception hierarchy is illustrated in &lt;a href=&quot;http://book.javanb.com/From-Java-To-Csharp-A-Developers-Guide/0321136225_ch13lev1sec2.html&quot;&gt;&amp;ldquo;C# exception hierarchy&amp;rdquo;&lt;/a&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;The Python exception hierarchy is documented in &lt;a href=&quot;http://docs.python.org/2/library/exceptions.html#exception-hierarchy&quot;&gt;&amp;ldquo;Exception Hierarchy&amp;rdquo;&lt;/a&gt;.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;Java has a few annoying examples where unexpected exceptions were marked as checked, burdening all subsequent callers. In particular &lt;code&gt;Object.clone()&lt;/code&gt; throws the checked &lt;code&gt;CloneNotSupportedException&lt;/code&gt;, making it hard to use. And Java&amp;rsquo;s reflection library throws the checked &lt;code&gt;IllegalAccessException&lt;/code&gt; and &lt;code&gt;InvocationTargetException&lt;/code&gt; whenever you try to &lt;code&gt;invoke()&lt;/code&gt; a method, neither of which are expected errors. And &lt;code&gt;Thread.sleep()&lt;/code&gt; throws the checked &lt;code&gt;InterruptedException&lt;/code&gt;. Now &lt;code&gt;IOException&lt;/code&gt;, thrown by all I/O functions, is legitimately a checked exception because it is an expected exception.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;Instead of documenting the guarantees after failure for individual functions, it also common to document an overall failure handling strategy for the entire system. For example most databases are documented as generally operating in a transactional fashion, with failed operations leaving the database in its original state. Of course some functions may deviate from the general policy, in which case the deviation should be documented.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;Unexpected and fatal exceptions, on the other hand, are &lt;em&gt;not&lt;/em&gt; typically part of a function&amp;rsquo;s API. As such, callers should not write exception handlers that depend on them.&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;In this circumstance a caller is forced to guess the exception type by parsing the exception&amp;rsquo;s message. However this solution is brittle since the message isn&amp;rsquo;t part of the API and could change in the future or vary depending on the current locale.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/06/01/handling-text-correctly</id>
   <title>Handling Text Correctly</title>
   <published>2013-06-01T00:00:00+00:00</published>
   <updated>2014-01-01T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/06/01/handling-text-correctly/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;A remarkable number of programs do not handle text in a reasonable fashion, which causes those programs to break when confronted with non-English characters and symbols. Even the standard libraries of most programming languages are not immune.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This chapter describes the foundation of how text handling works in software and gives examples of common pitfalls when working with text in real code. Upon completion you should be able to evaluate your favorite programming environment&amp;rsquo;s built-in support for handling text and be able to write programs that handle text correctly and consistently across operating systems.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;#characters-sets-and-encodings&quot;&gt;Characters, Sets, and Encodings&lt;/a&gt;&lt;/li&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#important-character-sets&quot;&gt;Important Character Sets&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unicode&quot;&gt;Unicode&lt;/a&gt;&lt;/li&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;#unicode-character-encodings&quot;&gt;Unicode Character Encodings&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/ul&gt;
    &lt;li&gt;&lt;a href=&quot;#common-mistakes-and-practical-tips&quot;&gt;Common Mistakes &amp;amp; Practical Tips&lt;/a&gt;&lt;/li&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#you-cannot-interpret-a-byte-array-as-a-string-without-knowing-its-encoding&quot;&gt;You cannot interpret a byte array as a string without knowing its encoding.&lt;/a&gt;&lt;/li&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;#reading-text-files&quot;&gt;Reading Text Files&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;#converting-between-bytes-and-strings&quot;&gt;Converting Between Bytes and Strings&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
      &lt;li&gt;&lt;a href=&quot;#a-char-in-your-favorite-language-is-probably-not-a-character&quot;&gt;A &quot;char&quot; (in your favorite language) is probably not a character.&lt;/a&gt;&lt;/li&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;#8-bit-chars&quot;&gt;8-bit chars&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;#16-bit-chars&quot;&gt;16-bit chars&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;#32-bit-chars&quot;&gt;32-bit chars and variable-bit chars&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/ul&gt;
    &lt;li&gt;&lt;a href=&quot;#end-of-line-sequences&quot;&gt;End of Line Sequences&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;characters-sets-and-encodings&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Characters, Sets, and Encodings&lt;/h2&gt;

&lt;p&gt;Text is made up of multiple &lt;strong&gt;characters&lt;/strong&gt; (or &lt;strong&gt;codepoints&lt;/strong&gt;&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;), each of which represents a different letter, symbol or punctuation mark. The word &amp;ldquo;Hello&amp;rdquo;, for example is made of the characters &amp;ldquo;H&amp;rdquo;, &amp;ldquo;e&amp;rdquo;, &amp;ldquo;l&amp;rdquo;, &amp;ldquo;l&amp;rdquo;, and &amp;ldquo;o&amp;rdquo;. This collection of characters is called a &lt;strong&gt;string&lt;/strong&gt;. Each character is assigned a number using a &lt;strong&gt;character set&lt;/strong&gt; (sometimes called a &lt;em&gt;code page&lt;/em&gt; or a &lt;em&gt;charset&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;For example the &lt;strong&gt;ASCII&lt;/strong&gt; character set assigns numbers in the range (0-127) for characters in most Western European languages.&lt;/p&gt;

&lt;div style=&quot;font-size: 20px; margin-left: 3em; font-family: monospace; margin-bottom: 12px; line-height: 1.1em;&quot;&gt;
H &amp;rarr; 72&lt;br/&gt;
e &amp;rarr; 101&lt;br/&gt; 
l &amp;rarr; 76&lt;br/&gt;
l &amp;rarr; 76&lt;br/&gt;
o &amp;rarr; 111
&lt;/div&gt;


&lt;p&gt;ASCII is one of the oldest character sets. Most other sets use the same mappings as ASCII, while defining additional mappings of their own for numbers above 127.&lt;/p&gt;

&lt;p&gt;After mapping a character to a number, that number is converted to an actual byte sequence for storage. The entire process of converting a character to a byte sequence is defined by a &lt;strong&gt;character encoding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since many character sets provide mappings to numbers in the range 0-255 (which fit in 8-bit bytes), you can output the character number as a single byte. For example, to output &amp;ldquo;Hello&amp;rdquo; in ASCII, you would emit the byte sequence:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;H  &lt;/th&gt;
&lt;th&gt; e   &lt;/th&gt;
&lt;th&gt; l  &lt;/th&gt;
&lt;th&gt; l  &lt;/th&gt;
&lt;th&gt; o&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;72 &lt;/td&gt;
&lt;td&gt; 101 &lt;/td&gt;
&lt;td&gt; 76 &lt;/td&gt;
&lt;td&gt; 76 &lt;/td&gt;
&lt;td&gt; 111&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;p&gt;Many English-speakers, being only familiar with the Western European character sets which are always encoded with individual 8-bits bytes, often use the terms &lt;em&gt;character set&lt;/em&gt; and &lt;em&gt;character encoding&lt;/em&gt; interchangably.&lt;/p&gt;

&lt;p&gt;However the East Asian languages such as Chinese, Japanese, and Korean (CJK) have many more than 256 characters, making it impossible to fit them in only 8-bit bytes. Therefore each character must be encoded using multiple bytes, possibly a variable number of bytes. Thus either a fixed-width encoding (often 16-bits per character) or a variable width encoding (with differing numbers of bytes per character) may be used.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;important-character-sets&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Important Character Sets&lt;/h3&gt;

&lt;p&gt;The following are the most prevalent non-Unicode character sets you are likely to encounter. All of these character sets are encoded with a single byte per character.&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Character Set                   &lt;/th&gt;
&lt;th&gt; Character Encoding&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ASCII                           &lt;/td&gt;
&lt;td&gt; single byte (7-bit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows-1252 (Windows Latin 1)  &lt;/td&gt;
&lt;td&gt; single byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ISO 8859-1 (ISO Latin 1)        &lt;/td&gt;
&lt;td&gt; single byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mac OS Roman                    &lt;/td&gt;
&lt;td&gt; single byte&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;p&gt;Informally (and in practice), these may also be described as character encodings. So a text file &amp;ldquo;in ASCII encoding&amp;rdquo; refers to a file in the ASCII character set with its standard single-byte encoding.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ASCII&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;7-bit character set for representing characters common to most Western European languages.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚠ Many programs and APIs that claim to input or output &amp;ldquo;ASCII&amp;rdquo; (or &amp;ldquo;ANSI&amp;rdquo;&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;) are actually unaware of character sets and will accept strings in whatever the operating system&amp;rsquo;s default character set happens to be (often Windows-1252).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows-1252&lt;/strong&gt; (AKA &lt;strong&gt;Windows Latin 1&lt;/strong&gt;)

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This is the default character set on English Windows systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISO 8859-1&lt;/strong&gt; (AKA &lt;strong&gt;ISO Latin 1&lt;/strong&gt;)

&lt;ul&gt;
&lt;li&gt;The default character set for web pages and other HTTP traffic.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚠ In practice this is &lt;em&gt;very&lt;/em&gt; frequently confused with &lt;b&gt;Windows-1252&lt;/b&gt;, which differs in only a handful of characters. In fact this confusion is to such a degree that the draft HTML 5 specification requires that documents advertised as ISO-8859-1 actually be parsed as Windows-1252.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mac OS Roman&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is the default character set on most Macintosh systems prior to Mac OS X.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Not every character set can represent every character in the world. For example Windows-1252 cannot represent any Chinese or Japanese characters, although GBK and Shift JIS respectively can. This means that you cannot in general mix text from two sources that uses a different character sets without converting to a new character set (that can represent all characters in both sets). Typically the Unicode character set (discussed below) is used for this purpose.&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Character Set                           &lt;/th&gt;
&lt;th&gt; Character Encoding&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows-932 (&amp;ldquo;Shift JIS&amp;rdquo;)&lt;!--[^WStd]--&gt; &lt;/td&gt;
&lt;td&gt; variable width, 1-2 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows-936 (&amp;ldquo;GBK&amp;rdquo;)                     &lt;/td&gt;
&lt;td&gt; variable width, 1-2 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;!--
[^WStd]: It should be noted that that the official Shift JIS and GBK specifications differ from their implementations in Windows. However it is the Windows implementations that have become the de-facto standards. Therefore if you see an unqualified reference to &quot;Shift JIS&quot;, it most likely refers to Windows-932 instead of the official standard.
--&gt;


&lt;p&gt;&lt;a id=&quot;unicode&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Unicode&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Unicode&lt;/strong&gt; is a character set just like ASCII or Windows-1252: it maps characters to numbers.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; However it is sufficiently important to justify special mention.&lt;/p&gt;

&lt;p&gt;The Unicode character set is designed to support all characters in all character sets that came before it, plus many more. If you can think of a character, it&amp;rsquo;s almost certainly in Unicode. (And if it isn&amp;rsquo;t, it&amp;rsquo;s likely not in any character set.) In this sense, Unicode can be viewed as the universal character set.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Any program written today that wishes to represent characters correctly should be using the Unicode character set and one of its associated encodings.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Originally, Unicode mapped characters to numbers in the range 0x0000-0xFFFF, requiring only 16 bits to represent each character. At that time it was possible to encode each Unicode character using a 2-byte fixed width encoding, known as &lt;strong&gt;UCS-2&lt;/strong&gt;. Many early Unicode-aware systems, such as Java, were designed around this original specification.&lt;/p&gt;

&lt;p&gt;In 1996, Unicode was extended to map characters to numbers in the larger range of 0x00000-0x10FFFF, requiring up to 20 bits per character. Thus UCS-2, being limited to 16-bits, was no longer capable of representing all Unicode characters. In its place arose the &lt;strong&gt;UTF-16&lt;/strong&gt; encoding which, like UCS-2, uses a single 16-bit value to represent characters in range 0x0000-0xFFFF (the &lt;strong&gt;basic multilingual plane&lt;/strong&gt;) and two 16-bit values to represent characters in range 0x10000-0x10FFFF (the &lt;strong&gt;supplemental planes&lt;/strong&gt;). And so many UCS-2 systems were retroactively upgraded to use UTF-16 in place of UCS-2.&lt;/p&gt;

&lt;p&gt;Today, UTF-16 is the most common in-memory representation for Unicode strings. However, many programs incorrectly treat individual 16-bit values from UTF-16 directly as characters, due to ignorance of UTF-16&amp;rsquo;s variable-width nature. In many cases this causes no problems, since most programs operate on strings and substrings opaquely, as opposed to working with individual characters. However problems will arise if unaware programs attempt to manipulate characters directly, such as by counting the number of characters in a string or by filtering individual characters.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;unicode-character-encodings&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Unicode Character Encodings&lt;/h4&gt;

&lt;p&gt;Unlike the other character sets discussed previously, the Unicode character set has &lt;em&gt;multiple&lt;/em&gt; different encodings.&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Character Set   &lt;/th&gt;
&lt;th&gt; Character Encoding    &lt;/th&gt;
&lt;th&gt; Character Encoding Scheme&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unicode         &lt;/td&gt;
&lt;td&gt; UTF-8                 &lt;/td&gt;
&lt;td&gt; variable width, 1-4 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt; UCS-2                 &lt;/td&gt;
&lt;td&gt; fixed width, 2 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt; UTF-16                &lt;/td&gt;
&lt;td&gt; variable width, 2 or 4 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt; UTF-32 / UCS-4        &lt;/td&gt;
&lt;td&gt; fixed width, 4 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UTF-8&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is the default on-disk encoding for most modern Unicode-aware programs.

&lt;ul&gt;
&lt;li&gt;Many text editors save in this format by default.&lt;/li&gt;
&lt;li&gt;Python 2.5+ source files are assumed to be UTF-8 by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It can represent any character in the Unicode character set, and thus any character in the world.&lt;/li&gt;
&lt;li&gt;It is compact, representing all ASCII characters as single bytes and most other characters as two bytes.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚠ Programs may optionally prepend a &lt;strong&gt;byte-order-mark (BOM)&lt;/strong&gt; at the beginning of a file to mark it as UTF-8. Most Windows programs do this, for example. Programs that input &lt;span class=&quot;nobr&quot;&gt;UTF-8&lt;/span&gt; files should be prepared to handle BOMs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UCS-2&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is the native encoding used by early Unicode-aware systems, such as Java 1.4 and below.&lt;/li&gt;
&lt;li&gt;It can only represent Unicode characters in the basic plane (0x0000-0xFFFF), but no higher.&lt;br/&gt;
In particular &lt;strong&gt;supplementary characters&lt;/strong&gt; in the supplementary planes (0x10000-0x10FFFF) cannot be represented. These are sometimes called &lt;strong&gt;astral characters&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many APIs that originally only supported UCS-2 were retroactively upgraded to use &lt;span class=&quot;nobr&quot;&gt;UTF-16&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UTF-16&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is the default in-memory encoding for most modern Unicode-aware systems, including Windows, Mac OS X, the Java 1.5+ runtime&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;, the .NET runtime (including C#), and Python 2.x&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;It can represent any character in the Unicode character set.&lt;/li&gt;
&lt;li&gt;Characters in the basic plane (0x0000-0xFFFF) are encoded as a single 16-bit value.&lt;br/&gt;
Supplementary characters (0x10000-0x10FFFF) are encoded as two 16-bit &lt;strong&gt;surrogate&lt;/strong&gt; values.&lt;/li&gt;
&lt;li&gt;⚠ It is common for code to incorrectly manipulate UTF-16 data as if it were fixed-width &lt;span class=&quot;nobr&quot;&gt;UCS-2&lt;span&gt; instead.&lt;/li&gt;
&lt;li&gt;⚠ Programs may optionally prepend a &lt;em&gt;byte-order-mark (BOM)&lt;/em&gt; at the beginning of a file to mark it as UTF-16 or to specify a byte-ordering other than big-endian. Programs that input &lt;span class=&quot;nobr&quot;&gt;UTF-16&lt;span&gt; files should be prepared to handle BOMs.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚠ Some outdated documentation and APIs may refer to the UTF-16 encoding as the &amp;ldquo;Unicode encoding&amp;rdquo;. Notably C#&amp;rsquo;s &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.text.unicodeencoding.aspx&quot;&gt;UnicodeEncoding&lt;/a&gt;, Mac OS X&amp;rsquo;s &lt;a href=&quot;http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSUnicodeStringEncoding&quot;&gt;NSUnicodeStringEncoding&lt;/a&gt; or Python 2.2-3.2&amp;rsquo;s &lt;code&gt;unicode&lt;/code&gt; type on &amp;ldquo;narrow&amp;rdquo; builds, which are the default.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UTF-32 / UCS-4&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is a fixed width encoding capable of representing any Unicode character directly as a 32-bit value.&lt;/li&gt;
&lt;li&gt;Because it is space inefficient, this encoding is rarely seen in practice.

&lt;ul&gt;
&lt;li&gt;Python 2.2-3.2 offers &amp;ldquo;wide&amp;rdquo; builds that use UTF-32.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;⚠ Programs may optionally prepend a &lt;em&gt;byte-order-mark (BOM)&lt;/em&gt; at the beginning of a file to mark it as UTF-32 or to specify a byte-ordering other than big-endian. Programs that input &lt;span class=&quot;nobr&quot;&gt;UTF-32&lt;/span&gt; files should be prepared to handle BOMs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;common-mistakes-and-practical-tips&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Common Mistakes &amp;amp; Practical Tips&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;you-cannot-interpret-a-byte-array-as-a-string-without-knowing-its-encoding&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;You cannot interpret a byte array as a string without knowing its encoding.&lt;/h3&gt;

&lt;p&gt;&lt;a id=&quot;reading-text-files&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Reading Text Files&lt;/h4&gt;

&lt;p&gt;You cannot read a text file correctly without knowing its encoding.&lt;/p&gt;

&lt;p&gt;If you do not specify an encoding explicitly when opening a text file, your language&amp;rsquo;s standard library or operating system will usually pick a default encoding, which depends on the spoken language it is running in, among other factors.&lt;/p&gt;

&lt;p&gt;Unfortunately most filesystems do not store the encoding of a text file.&lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; So there are a few options for determining an encoding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Define a particular encoding as the expected input.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For example, a receipt-processing program may explicitly document UTF-8 as the encoding for its input files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Look at the contents of the input file to auto-detect the encoding:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You could detect UTF byte-order-marks at the beginning of a file to automatically assume one of the UTF encodings.&lt;/li&gt;
&lt;li&gt;You could define a special syntax at the beginning of the input files to indicate the encoding.

&lt;ul&gt;
&lt;li&gt;XML uses a prelude at the top of a file to indicate what encoding it uses. For example &lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1252&quot;?&amp;gt;&lt;/code&gt; specifies that the document is in Window-1252 encoding. (Of course to even read this initial text, you have to make the working assumption that the top of the file is some encoding that is a superset of ASCII.)&lt;/li&gt;
&lt;li&gt;Python source files use a line such as &lt;code&gt;# -*- coding: utf-8 -*-&lt;/code&gt; to indicate the encoding is other than the default. (Python 2.0-2.4 uses Windows Latin 1 as the default encoding; Python 2.5-2.7 uses ASCII, Python 3.x uses UTF-8.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failing these options, you could fall back to a defined encoding (such as ASCII for Python source files) or to the operating system&amp;rsquo;s default encoding (which can vary).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always use the operating system&amp;rsquo;s default encoding.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is often the behavior if you use your favorite programming language&amp;rsquo;s default mechanism for reading a file, such as Java&amp;rsquo;s &lt;code&gt;FileReader&lt;/code&gt; class. (Interestingly, C#&amp;rsquo;s &lt;code&gt;StreamReader&lt;/code&gt; and &lt;code&gt;StreamWriter&lt;/code&gt; classes always use UTF-8 instead of the operating system default.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;converting-between-bytes-and-strings&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Converting Between Bytes and Strings&lt;/h4&gt;

&lt;p&gt;You cannot correctly convert a byte array to a string without specifying the encoding to use.&lt;/p&gt;

&lt;p&gt;Unfortunately many languages allow you to omit the encoding, and then will try to guess the encoding (usually incorrectly) if you fail to specify it.&lt;/p&gt;

&lt;p&gt;Consider the following Java program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;byte[] footBytes = {'f', 'u', (byte)0xC3, (byte)0x9F};
String footString = new String(footBytes);                    // WRONG: OS-dependent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This program will decode different strings on different operating systems! On Mac OS X and Linux where the platform&amp;rsquo;s default encoding is UTF-8, the correct result (&amp;ldquo;fuß&amp;rdquo;) will be obtained since the original bytes were encoded in UTF-8. However on Windows the bogus result &amp;ldquo;fuÃŸ&amp;rdquo; will be decoded because the default encoding is Windows-1252.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the fixed program, which specifies the UTF-8 encoding explicitly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;byte[] footBytes = {'f', 'u', (byte)0xC3, (byte)0x9F};
String footString = new String(footBytes, &quot;UTF-8&quot;);           // CORRECT
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As another example, consider the Java &lt;code&gt;InputStreamReader&lt;/code&gt; and &lt;code&gt;FileReader&lt;/code&gt; classes, both of which convert from byte streams to character streams.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;byte[] footBytes = {'f', 'u', (byte)0xC3, (byte)0x9F};
InputStream footStream = new ByteArrayInputStream(footBytes);
Reader footReader = new InputStreamReader(footStream);        // WRONG: OS-dependent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or the even more innocent-looking:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Reader footReader = new FileReader(&quot;foot.txt&quot;);               // WRONG: OS-dependent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Both of these examples are wrong for the same reason: they don&amp;rsquo;t specify the encoding.&lt;/p&gt;

&lt;p&gt;The former example can be fixed by adding &lt;code&gt;&quot;UTF-8&quot;&lt;/code&gt; as the second constructor argument:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;byte[] footBytes = {'f', 'u', (byte)0xC3, (byte)0x9F};
InputStream footStream = new ByteArrayInputStream(footBytes);
Reader footReader = new InputStreamReader(footStream, &quot;UTF-8&quot;);    // CORRECT
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fixing the second example unfortunately requires using an entirely different class since &lt;code&gt;FileReader&lt;/code&gt; has no constructer with an encoding parameter.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Reader footReader = new InputStreamReader(
    new FileInputStream(&quot;foot.txt&quot;), &quot;UTF-8&quot;);                // CORRECT
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course the same problems happen when encoding a string to a byte stream:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;String footString = &quot;fu\u00DF&quot;;
byte[] footBytes = footString.getBytes();                     // WRONG: OS-dependent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And when encoding a character stream to a byte stream:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ByteArrayOutputStream footStream = new ByteArrayOutputStream();
Writer footWriter = new OutputStreamWriter(footStream);       // WRONG: OS-dependent
footWriter.write(&quot;fu\u00DF&quot;);
byte[] footBytes = footStream.toByteArray();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And when writing to text files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Writer footWriter = new FileWriter(&quot;foot.txt&quot;);               // WRONG: OS-dependent
footWriter.write(&quot;fu\u00DF&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a id=&quot;a-char-in-your-favorite-language-is-probably-not-a-character&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;A &amp;ldquo;char&amp;rdquo; (in your favorite language) is probably not a character.&lt;/h3&gt;

&lt;p&gt;Many programming languages have a &amp;ldquo;char&amp;rdquo; datatype that is intended for representing a character. Usually this &amp;ldquo;char&amp;rdquo; datatype could do this effectively at the time the language was written but not in the present day, as the notion of a character has been extended over time.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;8-bit-chars&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;8-bit chars (C/C++)&lt;/h4&gt;

&lt;p&gt;In C/C++, a &amp;ldquo;char&amp;rdquo; holds one byte. When C was first invented, 8-bit fixed-width character encodings were the norm. Therefore a single &amp;ldquo;char&amp;rdquo; was able to represent a single character precisely. However with the advent of CJK languages and multi-byte encodings, this no longer worked. Therefore a C string by itself today can only be safely interpreted as a raw byte stream. As mentioned above, you can only process it properly if you know what encoding it is in.&lt;/p&gt;

&lt;p&gt;Without any further information, C string is often assumed to be in the operating system&amp;rsquo;s default encoding, although you cannot be sure. The correct encoding to use depends on where the string was input from.&lt;/p&gt;

&lt;p&gt;A program can work with strings in a few ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Choose a particular in-memory encoding that all functions should use.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;All foreign strings will be converted to this encoding at the time of input (regardless of source). And upon output, strings will be converted to the appropriate proper output encoding.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UTF-8 and UTF-16 are both good candidates for such an in-memory encoding since they can both represent the full repertoire of Unicode characters. Therefore you won&amp;rsquo;t lose any data by converting to/from them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;UTF-8 is compact and a superset of ASCII, so you can pass UTF-8 strings to brain-dead functions that are encoding unaware and get correct behavior as long as only ASCII characters are being used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UTF-16 is convenient because functions that are unaware of supplementary characters will still get correct behavior as long as basic-plane Unicode characters are used, which are the most common.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pass around the text encoding around with the underlying byte array, possibly with a custom string datatype.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;No encoding conversion overhead with reading the input stream.&lt;/li&gt;
&lt;li&gt;Cannot mix text with different encodings.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ruby takes this approach with its built-in &lt;code&gt;String&lt;/code&gt; type.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blithely ignore encoding issues altogether and get unexpected results when working with international characters.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Many programs written in languages where the default string type is not Unicode take this option out of ignorance. In particular this includes many programs in C, PHP, and &lt;span class=&quot;nobr&quot;&gt;Python 2.x&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Gotchas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beware of methods that take exactly one &lt;code&gt;char&lt;/code&gt; or return exactly one &lt;code&gt;char&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;They almost certainly aren&amp;rsquo;t aware of non-ASCII or Unicode characters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Beware of any libraries that don&amp;rsquo;t document what text encoding it assumes.

&lt;ul&gt;
&lt;li&gt;They almost certainly aren&amp;rsquo;t aware of non-ASCII or Unicode characters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;16-bit-chars&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;16-bit chars (Java, C#, Objective-C, Python 2.2-3.2, C/C++&amp;rsquo;s &lt;code&gt;wchar&lt;/code&gt;)&lt;/h4&gt;

&lt;p&gt;Java and C#&amp;rsquo;s &lt;code&gt;char&lt;/code&gt; are 16-bits wide. So are C/C++&amp;rsquo;s &lt;code&gt;wchar&lt;/code&gt; and Mac OS X&amp;rsquo;s &lt;code&gt;unichar&lt;/code&gt;. And so are the elements of a Python 2.x string when it is compiled in the default &amp;ldquo;narrow&amp;rdquo; mode.&lt;/p&gt;

&lt;p&gt;16-bits is sufficient to hold a Unicode character in the basic plane (0x0000-0xFFFF) but not an supplementary character in a supplemental plane (0x10000-0x10FFFF). In the case of these languages, a &lt;code&gt;char&lt;/code&gt; represents a single UTF-16 code unit (i.e. either a character in the basic plane or a surrogate) as opposed to an actual character.&lt;/p&gt;

&lt;p&gt;Therefore text-aware programs in these languages need to be particularly careful to deal with supplementary characters correctly, since those characters cannot fit into a single &lt;code&gt;char&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;Here is a typical Java program that is unaware of supplementary characters:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;String str = &quot;Hello&quot;;
for (int i=0, n=str.length(); i&amp;lt;n; i++) {
    // WRONG: Does not handle characters outside the basic plane (0x0000-0xFFFF)
    char c = str.charAt(i);

    // ... Do something with the character, like filtering out invalid characters.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here is a much-longer but correct version that correctly identifies surrogates and decodes them to supplementary characters correctly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;String str = &quot;Hello&quot;;
for (int i=0, n=str.length(); i&amp;lt;n; i++) {
    char c1 = str.charAt(i);

    // CORRECT. Handles all Unicode characters.
    int codepoint;
    if (Character.isHighSurrogate(c1)) {
        if (i+1 &amp;lt; n) {
            char c2 = str.charAt(i+1);
            if (Character.isLowSurrogate(c2)) {
                // Surrogate pair
                codepoint = Character.toCodePoint(c1, c2);

                i++;
            } else {
                // High-surrogate alone
                codepoint = (int) c1;
            }
        } else {
            // High-surrogate alone at end of string
            codepoint = (int) c1;
        }
    } else {
        // Not a surrogate pair
        codepoint = (int) c1;
    }

    // ... Do something with the character, like filtering out invalid characters.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gotchas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beware of methods that take exactly one &lt;code&gt;char&lt;/code&gt; or return exactly one &lt;code&gt;char&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;They almost certainly aren&amp;rsquo;t aware of supplementary characters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t iterate over the characters in a &amp;ldquo;string&amp;rdquo; by iterating over the &lt;code&gt;char&lt;/code&gt;s.

&lt;ul&gt;
&lt;li&gt;Instead you have to use a loop like the above to iterate over the true characters.&lt;br/&gt;
This example stores the true character in the &lt;code&gt;codepoint&lt;/code&gt; variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t get the i&lt;sup&gt;th&lt;/sup&gt; character of a &amp;ldquo;string&amp;rdquo; by getting the i&lt;sup&gt;th&lt;/sup&gt; &lt;code&gt;char&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;No general workaround.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;32-bit-chars&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;32-bit chars and variable-bit chars (Python 3.3+, Haskell)&lt;/h4&gt;

&lt;p&gt;If you&amp;rsquo;re fortunate enough to work in an environment with 32-bit or variable-bit chars then your &lt;code&gt;char&lt;/code&gt; is in fact a character. Horray!&lt;/p&gt;

&lt;p&gt;The only popular environment I know of with real characters is Python 3.3+, or Python 2.2-3.2 when configured to be in &amp;ldquo;wide&amp;rdquo; mode (which is not the default).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;end-of-line-sequences&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;End of Line Sequences&lt;/h2&gt;

&lt;p&gt;Improper handling of end-of-line (EOL) sequences is not uncommon.&lt;/p&gt;

&lt;p&gt;There are three common ways to end a line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux: &lt;code&gt;\n&lt;/code&gt; (line feed alone)&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;\r\n&lt;/code&gt; (carriage return + line feed)&lt;/li&gt;
&lt;li&gt;Mac OS 9: &lt;code&gt;\r&lt;/code&gt; (carriage return alone)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It is possible for multiple styles to occur in the same file or string.&lt;/p&gt;

&lt;p&gt;It should also be noted that the last line in a file or string might or might not be followed by an EOL sequence. Therefore you can&amp;rsquo;t assume that every line ends with an EOL sequence.&lt;/p&gt;

&lt;p&gt;As the following examples demonstrate, you need to read your language&amp;rsquo;s documentation carefully if you want to process lines in a consistent fashion.&lt;/p&gt;

&lt;h4&gt;Java Line Reader Example&lt;/h4&gt;

&lt;p&gt;Consider the following Java program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Prints the specified file to standard output.
public static void main(String[] args) {
    String filePath = args[0];
    BufferedReader lineReader =
        new BufferedReader(new FileReader(filePath, &quot;UTF-8&quot;));
    try {
        String nextLine;
        while ((nextLine = lineReader.readLine()) != null) {
            System.out.println(nextLine);
        }
    } finally {
        lineReader.close();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;BufferedReader&lt;/code&gt; class can deal with all end-of-line sequences. Therefore this program is resilient against mixed input.&lt;/p&gt;

&lt;p&gt;However &lt;code&gt;println&lt;/code&gt; (in the &lt;code&gt;PrintWriter&lt;/code&gt; class) emits the OS-specific end-of-line sequence, which means that this program will have different output on different operating systems. Not necessarily what you&amp;rsquo;d expect.&lt;/p&gt;

&lt;h4&gt;Python 2.x Line Reader Example&lt;/h4&gt;

&lt;p&gt;Consider the following Python 2.x program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import codecs

file_path = sys.argv[1]
with codecs.open(file_path, 'rb', 'utf-8') as stream:
    for line_with_terminator in stream:
        line = line_with_terminator.rstrip(u'\r\n')    # remove any trailing '\r' and '\n's
        print line
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that in the Python version it is necessary to explicitly remove the &lt;code&gt;\r&lt;/code&gt; and &lt;code&gt;\n&lt;/code&gt; characters, since Python&amp;rsquo;s line iteration behavior is to return the entire line plus the end-of-line sequence (if available).&lt;/p&gt;

&lt;p&gt;Python&amp;rsquo;s &lt;code&gt;print&lt;/code&gt; statement always uses &lt;code&gt;\n&lt;/code&gt; as the end-of-line sequence, regardless of what OS it is running on. It&amp;rsquo;s nice that this is a consistent behavior, but it might not be what you expect if you are developing on Windows.&lt;/p&gt;

&lt;p&gt;Here is perhaps a more typical program that fails to handle the last line correctly if it doesn&amp;rsquo;t end with an EOL sequence:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import codecs

file_path = sys.argv[1]
with open(file_path, 'rU') as stream:     # the U mode converts all line endings to '\n'
    for line_with_terminator in stream:
        # WRONG: If last line lack an EOL this will chop off its trailing character improperly
        line = line_with_terminator[:-1]  # remove trailing '\n'
        # WRONG: Treating a bytestring as if it were a Unicode string
        print line
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Errors like this explain why lots of Unix programs warn about or get confused by files that don&amp;rsquo;t end with a final EOL.&lt;/p&gt;

&lt;p&gt;And here is another typical variation that does not handle end-of-line sequences properly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import codecs

file_path = sys.argv[1]
with open(file_path, 'rb') as stream:
    for line_with_terminator in stream:
        # WRONG: Assumes EOL is one byte long, which is incorrect on Windows
        line = line_with_terminator[:-1]  # remove trailing '\n'
        # WRONG: Treating a bytestring as if it were a Unicode string
        print line
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This kind of program will get extra &lt;code&gt;\r&lt;/code&gt; characters on the end of each line when run on Windows. It also fails to handle final lines that lack an EOL.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;summary&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;Working with text is tricky. Your programming language probably has default handling that isn&amp;rsquo;t quite what you want (or expect) so always read the documentation carefully. And if your program is intended to be usable in multiple languages, you actually should write tests that check for proper handling of Unicode characters.&lt;/p&gt;

&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Series
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        This article is part of the &lt;a href=&quot;/articles/2013/05/11/book-outline/&quot;&gt;Programming for Perfectionists&lt;/a&gt; series.
    &lt;/p&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Updates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2014-01-01:

&lt;ul&gt;
&lt;li&gt;Add introduction.&lt;/li&gt;
&lt;li&gt;Spell out how to add encoding parameter to &lt;code&gt;FileReader&lt;/code&gt; and &lt;code&gt;InputStreamReader&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;See &lt;a href=&quot;http://mortoray.com/2013/11/27/the-string-type-is-broken/&quot;&gt;The String Type is Broken&lt;/a&gt; for examples of how the standard libraries of various languages mishandle text.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;To be precise, the definition of &lt;em&gt;character&lt;/em&gt; used here is exactly the same as a &lt;em&gt;Unicode codepoint&lt;/em&gt;, for those readers who are already familiar with Unicode.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Windows documentation often refers to the default character set (or sometimes the ASCII character set) as the &amp;ldquo;ANSI encoding&amp;rdquo;. This is misleading since this is not a single concrete encoding and has nothing to do with the ANSI standards body. For example, the Save dialog in Windows Notepad (in Windows 7) and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/cc231241(v=prot.10).aspx&quot;&gt;Unicode Versus ANSI String Representations&lt;/a&gt; use &amp;ldquo;ANSI&amp;rdquo; to refer to the default encoding, whereas &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa368046(v=vs.85).aspx&quot;&gt;Copy a Unicode File to an ANSI File&lt;/a&gt; uses &amp;ldquo;ANSI&amp;rdquo; to refer to the ASCII encoding.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;&lt;a href=&quot;http://dev.w3.org/html5/spec/Overview.html#character-encodings-0&quot;&gt;HTML 5 Draft Recommendation — 12 April 2010, 8.1 Character encodings&lt;/a&gt;, retrieved 2010-04-12.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;The full Unicode standard also covers a wide variety of rules related to handling characters, such as sorting, rendering, and other operations. For our purposes though, we are only concerned with the Unicode character set.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;Compare the documentation for java.lang.String between &lt;a href=&quot;http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/String.html&quot;&gt;Java 1.4&lt;/a&gt; and &lt;a href=&quot;http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html&quot;&gt;Java 1.5&lt;/a&gt;. The 1.5 documentation clearly states UTF-16 as the internal string encoding.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;&lt;a href=&quot;http://www.python.org/dev/peps/pep-0261/&quot;&gt;PEP 261&lt;/a&gt; describes Python 2.x&amp;rsquo;s Unicode handling with respect to characters in the supplementary planes. &amp;ldquo;Narrow&amp;rdquo; Python builds (the default) use UTF-16 internally; &amp;ldquo;wide&amp;rdquo; Python builds use UTF-32 internally. (The distinction between narrow and wide builds disappeared in Python 3.3.)&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;The HFS filesystem used in Mac OS 9 and Mac OS X is one of the few filesystems that stores the encoding of text files as file metadata. However I think almost no modern OS X program is aware of this.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/05/28/rdiscount-2.1.6-released</id>
   <title>RDiscount 2.1.6 released</title>
   <published>2013-05-28T00:00:00+00:00</published>
   <updated>2013-05-28T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/05/28/rdiscount-2.1.6-released/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;There are several new features in &lt;a href=&quot;/projects/rdiscount/&quot;&gt;RDiscount&lt;/a&gt; 2.1.6. My favorite is fenced code blocks.&lt;/p&gt;

&lt;p&gt;Update to the latest version with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem update rdiscount
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;RDiscount now has feature parity with the latest Discount release.&lt;/p&gt;

&lt;h2&gt;What&amp;rsquo;s New?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fenced code blocks

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.github.com/github-flavored-markdown/&quot;&gt;backtick-delimited&lt;/a&gt; - from &lt;em&gt;GitHub Flavored Markdown&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://michelf.ca/projects/php-markdown/extra/#fenced-code-blocks&quot;&gt;tilde-delimited&lt;/a&gt; - from &lt;em&gt;PHP Markdown Extra&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New extensions:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:no_superscript&lt;/code&gt; - Disables superscript processing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:no_strikethrough&lt;/code&gt; - Disables strikethrough processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;License changed from 4-clause BSD to the more-permissive 3-clause BSD.&lt;/li&gt;
&lt;li&gt;Fix &lt;code&gt;--&lt;/code&gt; and &lt;code&gt;---&lt;/code&gt; to be converted to &lt;code&gt;&amp;amp;ndash;&lt;/code&gt; and &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; correctly.&lt;/li&gt;
&lt;li&gt;Fix handling of tables that have leading and trailing pipe characters.&lt;/li&gt;
&lt;li&gt;Fix generated table of contents to be valid HTML.&lt;br/&gt;
Handling of special characters in headings is also improved.&lt;/li&gt;
&lt;li&gt;Fix recognition of HTML tags that contain &lt;code&gt;-&lt;/code&gt; or &lt;code&gt;_&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;What&amp;rsquo;s Next?&lt;/h2&gt;

&lt;p&gt;Only David Loren Parsons knows.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; :-)&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/02/rdiscount-2.0.7-released/&quot;&gt;RDiscount 2.0.7 released&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Release notes for the previous release of RDiscount.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2012/12/16/why-i-no-longer-use-drupal/&quot;&gt;Why I no longer use Drupal&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Why Jekyll (and not Drupal) is awesome for making a personal website or blog.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Jekyll can use RDiscount for Markdown rendering.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;David Loren Parsons is the author and maintainer of the Discount library underlying RDiscount.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/05/12/implicit-partial-application-and-currying-considered-harmful</id>
   <title>Implicit Partial Application Considered Harmful</title>
   <published>2013-05-12T00:00:00+00:00</published>
   <updated>2013-05-12T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/05/12/implicit-partial-application-and-currying-considered-harmful/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Audience
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        I assume familiarity with the Haskell programming language or some other language that supports calling a function with less arguments than the function's signature requires. This is called &quot;partial application of a function&quot;.
    &lt;/p&gt;
&lt;/div&gt;


&lt;p&gt;Consider the following function-call expression in Haskell:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(alpha beta gamma)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What can be deduced?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alpha&lt;/code&gt; is a function (either imported or in a variable).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In most languages (that disallow implicit partial application) you could additionally deduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alpha&lt;/code&gt; takes exactly 2 arguments&lt;/li&gt;
&lt;li&gt;The expression&amp;rsquo;s return type matches that of &lt;code&gt;alpha&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Neither of those two properties are necessarily true in Haskell.&lt;/p&gt;

&lt;h3&gt;Case 1: alpha takes exactly 2 arguments&lt;/h3&gt;

&lt;p&gt;In this case, the expression behaves as you&amp;rsquo;d expect in any other language. In particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alpha&lt;/code&gt; takes exactly 2 arguments&lt;/li&gt;
&lt;li&gt;The expression&amp;rsquo;s return type matches that of &lt;code&gt;alpha&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Case 2: alpha takes more than 2 arguments&lt;/h3&gt;

&lt;p&gt;In this case, the expression is a partial application of &lt;code&gt;alpha&lt;/code&gt;, and would be perhaps better read as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(\ ... -&amp;gt; alpha beta gamma ...)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or, in a more C-like notation:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;function (...) { return alpha(beta, gamma, ...); }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Thus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alpha&lt;/code&gt; takes exactly 2+K arguments, for some unknown K.&lt;/li&gt;
&lt;li&gt;The expression returns a function of K arguments.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Case 3: alpha takes less than 2 arguments&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s say &lt;code&gt;alpha&lt;/code&gt; takes 1 argument. This would be intuitively read as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;((alpha beta) gamma)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After this reformulation you need to recursively examine the new expression.&lt;/p&gt;

&lt;p&gt;In this example, we can deduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(alpha beta)&lt;/code&gt; returns an anonymous function of (at least) 1 argument.&lt;/li&gt;
&lt;li&gt;If this anonymous function takes 1 argument, then it is just called with &lt;code&gt;gamma&lt;/code&gt;, and the original expression&amp;rsquo;s return type matches the return type of the anonymous function.&lt;/li&gt;
&lt;li&gt;If this anonymous function takes more than one argument (1+K), then it is partially applied to &lt;code&gt;gamma&lt;/code&gt;, and yet another anonymous function (that takes K parameters) is returned as the result of the original expression.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;What a mess. If &lt;code&gt;alpha&lt;/code&gt; does not in fact take two arguments then I have to exert non-trivial effort to derive the type of the expression - or even what the expression semantics are.&lt;/p&gt;

&lt;h2&gt;Reducing the Ambiguity&lt;/h2&gt;

&lt;p&gt;There are two ways I can see to simplify these weird cases:&lt;/p&gt;

&lt;h3&gt;Make partial application &lt;em&gt;explicit&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;Then we would see syntax like:&lt;/p&gt;

&lt;pre&gt;
-- alpha takes 2 arguments
-- return type matches that of alpha
(alpha beta gamma)

-- alpha takes 2+K arguments;
-- return type is a partially applied K-argument function
(alpha beta gamma ...)   

-- alpha takes 1 argument and returns a 1-argument function;
-- expression's return type matches that of the 1-argument function
((alpha beta) gamma)

-- alpha takes 1 argument and returns a (1+K)-argument function;
-- expression's return type is a partially applied K-argument function
((alpha beta) gamma ...)
&lt;/pre&gt;


&lt;p&gt;Notice that each conceptually different case now has a unique syntactic representation - it&amp;rsquo;s no longer just &lt;code&gt;(alpha beta gamma)&lt;/code&gt; for all cases.&lt;/p&gt;

&lt;h3&gt;Use a grouping operator for function application&lt;/h3&gt;

&lt;p&gt;For example parentheses could be used instead of a space to signify function calls.&lt;/p&gt;

&lt;p&gt;Using a grouping operator syntactically prohibits relying on the left-associativity of space for partial function application, since a grouping operator doesn&amp;rsquo;t have associativity.&lt;/p&gt;

&lt;p&gt;If you combined this suggestion with the explicit syntax extension above, you would get syntax like:&lt;/p&gt;

&lt;pre&gt;
-- alpha takes 2 arguments
-- return type matches that of alpha
alpha(beta, gamma)

-- alpha takes 2+K arguments;
-- return type is a partially applied K-argument function
alpha(beta, gamma, ...)   

-- alpha takes 1 argument and returns a 1-argument function;
-- expression's return type matches that of the 1-argument function
alpha(beta)(gamma)

-- alpha takes 1 argument and returns a (1+K)-argument function;
-- expression's return type is a partially applied K-argument function
alpha(beta)(gamma, ...)
&lt;/pre&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes several other programming languages and their unique features.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/20/visual-guide-to-programming-language-properties/&quot;&gt;Visual Guide to Programming Language Properties&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Visualizes how various programming language properties interact.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Appendix&lt;/h2&gt;

&lt;p&gt;I originally got bitten by this syntactic ambiguity when trying to decipher the meaning of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(flip (/) 20)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I was not previously familar with &lt;code&gt;flip&lt;/code&gt; and so I assumed that it took two arguments, a function (namely &lt;code&gt;(/)&lt;/code&gt;) and a non-function (namely &lt;code&gt;20&lt;/code&gt;). And that it probably returned a function, since its surrounding context expected a function.&lt;/p&gt;

&lt;p&gt;In fact &lt;code&gt;flip&lt;/code&gt; takes only one argument and thus is more clearly written as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;((flip (/)) 20)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And inlined further to be the lower-order:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(\x -&amp;gt; x / 20)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And, if desired, further rewritten to be the more-compact:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(/ 20)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This last form uses partial application to fill in the first argument of &lt;code&gt;/&lt;/code&gt;, which is obvious since &lt;code&gt;/&lt;/code&gt; is a well-known built-in infix operator that requires an unspecified left argument.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/05/11/book-outline</id>
   <title>Programming for Perfectionists (P4P): A Book Outline</title>
   <published>2013-05-11T00:00:00+00:00</published>
   <updated>2013-05-11T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/05/11/book-outline/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I&amp;rsquo;ve read a lot of programming books. Many focus on teaching a particular language or tool, or are for teaching beginner developers the ropes. Precious few are designed to bring intermediate developers up to an advanced level. It&amp;rsquo;s time to change that.&lt;/p&gt;

&lt;p&gt;Here is an outline of a book I would like to write. I will probably try writing some of these sections and chapters as future article posts. When that happens, each section below will be replaced with a link to the associated article.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Programming for Perfectionists&amp;rdquo; is the working title for the book and may be revised later.&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#fundamentals&quot;&gt;Fundamentals&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#representations&quot;&gt;Representations&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#numbers&quot;&gt;Numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#text&quot;&gt;Text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#color&quot;&gt;Color&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pictures&quot;&gt;Pictures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sound&quot;&gt;Sound&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#time&quot;&gt;Time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#video&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#collections&quot;&gt;Collections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#error-handling&quot;&gt;Error Handling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#concurrency&quot;&gt;Concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#memory-management&quot;&gt;Memory Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#languages&quot;&gt;Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#comparing-programming-languages&quot;&gt;Comparing Programming Languages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#programming-paradigms&quot;&gt;Programming Paradigms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#process&quot;&gt;Process&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#collaborative-software-development&quot;&gt;Collaborative Software Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#code-conventions&quot;&gt;Code Conventions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#communicating-software-designs&quot;&gt;Communicating Software Designs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#detecting-defects-early&quot;&gt;Detecting Defects Early (Testing)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#improving-code-quality&quot;&gt;Improving Code Quality (Basic Refactoring)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#debugging-techniques&quot;&gt;Debugging Techniques&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#profiling-instrumentation&quot;&gt;Profiling/Instrumentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#maintaining-legacy-code-safely&quot;&gt;Maintaining Legacy Code Safely (Advanced Refactoring)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#other&quot;&gt;Other&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#persistence&quot;&gt;Persistence&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#comments&quot;&gt;Comments?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#progress&quot;&gt;Progress&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;introduction&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;The purpose of this book is to provide a &lt;em&gt;wide and shallow&lt;/em&gt; overview of important concepts in real-world software development. As such the treatment of various topics will not be comprehensive. Entire books have been written on the topic of each chapter, and appropriate references will be provided where appropriate.&lt;/p&gt;

&lt;p&gt;This book will not teach specific tools, languages, or programs in depth. It deals in concepts and patterns. However references to specific tools and languages will be provided liberally in concrete examples.&lt;/p&gt;

&lt;p&gt;Many concepts presented here are ones that I feel are missing from the traditional &amp;ldquo;computer science&amp;rdquo; curriculum, yet which I feel to be vital to understand when working with real-world software.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;fundamentals&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Fundamentals&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;representations&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Representations&lt;/h3&gt;

&lt;p&gt;Many developers do not understand the common ways of representing various kinds of real-world data, such as text, integers, color, and time. This leads to errors such as munging of international characters, integer overflow vulnerabilities, ignorance of color correction, and bugs that only trigger at midnight on leap years.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a id=&quot;numbers&quot;&gt;&lt;/a&gt;&lt;strong&gt;Numbers&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Integers

&lt;ul&gt;
&lt;li&gt;Fixed-precision 2&amp;rsquo;s complement&lt;/li&gt;
&lt;li&gt;Arbitrary Precision Integers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Decimals

&lt;ul&gt;
&lt;li&gt;Floating Point&lt;/li&gt;
&lt;li&gt;Fixed Point&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a id=&quot;text&quot;&gt;&lt;/a&gt;&lt;a href=&quot;/articles/2013/06/01/handling-text-correctly/&quot;&gt;&lt;strong&gt;Text&lt;/strong&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Characters and Codepoints&lt;/li&gt;
&lt;li&gt;Text Encodings

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;ANSI&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Unicode, UTF-8, UCS-2, UTF-16

&lt;ul&gt;
&lt;li&gt;Basic Multilingual Plane, Astral Characters&lt;/li&gt;
&lt;li&gt;BOM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Characters&amp;rdquo; and &amp;ldquo;Strings&amp;rdquo; in popular programming languages&lt;/li&gt;
&lt;li&gt;Line-ending sequences&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a id=&quot;color&quot;&gt;&lt;/a&gt;&lt;strong&gt;Color&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Color Models, &amp;ldquo;RGB&amp;rdquo;, Colorspaces, CIE, Gamma&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a id=&quot;pictures&quot;&gt;&lt;/a&gt;&lt;strong&gt;Pictures&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Resolution

&lt;ul&gt;
&lt;li&gt;Magic: 72 dpi and 96 dpi&lt;/li&gt;
&lt;li&gt;Resolution Independence&lt;/li&gt;
&lt;li&gt;Pixel Doubling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Non-Square Pixels (ex: NTSC)&lt;/li&gt;
&lt;li&gt;Anamorphic Projections&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a id=&quot;sound&quot;&gt;&lt;/a&gt;&lt;strong&gt;Sound&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a id=&quot;time&quot;&gt;&lt;/a&gt;&lt;strong&gt;Time&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a id=&quot;video&quot;&gt;&lt;/a&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;collections&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Collections&lt;/h3&gt;

&lt;p&gt;Collections are the backbone for representing compound data in any programming language. Specific implementations are covered in great detail in most any traditional CS textbook. However there are a number of more advanced collections which are useful for tough problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2015/08/08/algorithms-101/&quot;&gt;&lt;strong&gt;Basic Collections&lt;/strong&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Arrays

&lt;ul&gt;
&lt;li&gt;Bit Vectors&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lists

&lt;ul&gt;
&lt;li&gt;Array lists&lt;/li&gt;
&lt;li&gt;Linked lists&lt;/li&gt;
&lt;li&gt;Linked lists of arbitrary objects&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sets

&lt;ul&gt;
&lt;li&gt;Hash set&lt;/li&gt;
&lt;li&gt;Linked hash set&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sorted Sets

&lt;ul&gt;
&lt;li&gt;Red &amp;amp; black trees&lt;/li&gt;
&lt;li&gt;Heaps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Maps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Collections&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Bags

&lt;ul&gt;
&lt;li&gt;Counted Bags&lt;/li&gt;
&lt;li&gt;Partitioning Bags&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Multimaps&lt;/li&gt;
&lt;li&gt;Bidi Multimaps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Data Structures&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Trees&lt;/li&gt;
&lt;li&gt;Graphs (including: directed, multi)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;error-handling&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;/articles/2013/07/13/error-handling/&quot;&gt;Error Handling&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;There are many more ways for a program to fail than succeed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Signaling (Error Codes vs. Exceptions vs. Sentinels)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Sentinels - null, 0, -1, false&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guarantees after failure&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;In original state (Atomic, Transactional)&lt;/li&gt;
&lt;li&gt;In different but valid state&lt;/li&gt;
&lt;li&gt;In different and potentially illegal state&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Behaviors upon failure&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Delegate to caller&lt;/li&gt;
&lt;li&gt;Handle internally

&lt;ul&gt;
&lt;li&gt;Aside: Minix is the extreme of this approach.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Exit program

&lt;ul&gt;
&lt;li&gt;Linux Kernel: panic()&lt;/li&gt;
&lt;li&gt;Python, PHP: die()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Display to user&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Locality &amp;amp; Failing Fast&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Assertions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Designing Error Messages&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Seriousness&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Expected - &lt;code&gt;Exception&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Unexpected - &lt;code&gt;RuntimeException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Fatal - &lt;code&gt;Error&lt;/code&gt; (esp. &lt;code&gt;OutOfMemoryError&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;Aside: Certain programs are actually designed to handle OOM errors (ex: SQLite). Most are not.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Bonus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Checked Exceptions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exception Wrapping&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;concurrency&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Concurrency&lt;/h3&gt;

&lt;p&gt;Early languages like C pretend that threads don&amp;rsquo;t even exist. And even amidst the multi-core systems today, many programmers would like to pretend that concurrent execution doesn&amp;rsquo;t exist. A huge number of concurrency-related bugs are found in production code today.&lt;/p&gt;

&lt;p&gt;Many developers are familiar with the &amp;ldquo;shared memory &amp;amp; locks&amp;rdquo; model used by most mainstream programming languages for working with concurrency. This model unfortunately makes it very easy to introduce bugs, and these bugs are often difficult to detect since they depend on the precise ordering of randomly-ordered events. Deadlocks and livelocks also lurk to trip the unwary. This and other more-robust models will be presented here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terminology&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Processes, Threads, and Green Threads&lt;/li&gt;
&lt;li&gt;Concurrency vs. Parallelism&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared Memory &amp;amp; Locks Model&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Thread Safe vs. Thread Unsafe vs. Thread Hostile&lt;/li&gt;
&lt;li&gt;Deadlocks, Livelocks, and Lock Hierarchies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apartment Threading&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Thread Affinity&lt;/li&gt;
&lt;li&gt;Run Loops&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actor Model&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Immutability&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Read-Copy-Update&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;memory-management&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Memory Management&lt;/h3&gt;

&lt;p&gt;Tradeoffs should be described for each of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Manual Memory Management&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Ownership - &amp;ldquo;Own &amp;amp; Borrow&amp;rdquo; Model&lt;/li&gt;
&lt;li&gt;Hierarchy, Composites vs. Aggregates&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reference Counting&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Automatic Reference Counting&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Garbage Collection&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Generational Collectors&lt;/li&gt;
&lt;li&gt;Mark &amp;amp; Sweep&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Bonus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Special-Purpose Memory Allocators&lt;/strong&gt; (to reduce calls to system&amp;rsquo;s malloc)

&lt;ul&gt;
&lt;li&gt;Slab Allocaters&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;languages&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Languages&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;comparing-programming-languages&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Comparing Programming Languages &lt;small&gt;(The Right Tool for the Right Job)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;A programming language is a tool for getting work done. Some tools are better at certain tasks than others. Thus picking your tool wisely for the task at hand will save you effort down the road.&lt;/p&gt;

&lt;p&gt;It should also be noted that a programming language does not stand alone; it comes with an entire ecosystem of tools and people along with it. Such ecosystems often cater to a particular domain and make it easier to work with programs in that domain.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native Development (Desktop, Mobile, and Embedded)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;C/C++ - lingua franca; easiest to bind to OS; hand-optimized performance-critical code&lt;/li&gt;
&lt;li&gt;Java - rich cross-platform development (including GUIs); server programming&lt;/li&gt;
&lt;li&gt;Python - rich cross-platform CLI scripting; text &amp;amp; data processing&lt;/li&gt;
&lt;li&gt;C# - rich Windows app programming&lt;/li&gt;
&lt;li&gt;Objective-C - native OS X development; native iOS development&lt;/li&gt;
&lt;li&gt;PowerShell - Windows CLI scripting&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Development (Server-Side)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;PHP - web application prototyping; most widely deployed server-side scripting language

&lt;ul&gt;
&lt;li&gt;Java &amp;amp; JSP - Java&amp;rsquo;s clone of PHP&lt;/li&gt;
&lt;li&gt;C# &amp;amp; ASP.NET - Microsoft&amp;rsquo;s clone of PHP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ruby &amp;amp; Ruby on Rails - bleeding-edge full-stack web framework&lt;/li&gt;
&lt;li&gt;Python &amp;amp; Django - mature full-stack web framework; rapid development; excellent ORM&lt;/li&gt;
&lt;li&gt;Python &amp;amp; web2py - mature full-stack web framework

&lt;ul&gt;
&lt;li&gt;Anecdotal evidence suggests PHP refugees prefer web2py over Django,
probably because it uses implicit behavior (i.e. magic) to avoid boilerplate.
In contrast Django&amp;rsquo;s philosophy is &amp;ldquo;explicit is better than implicit&amp;rdquo;,
which is more in line with general Python philosophy.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Python &amp;amp; (lots of choices) - lightweight web framework; for maximum control

&lt;ul&gt;
&lt;li&gt;Pyramid&lt;/li&gt;
&lt;li&gt;Flask&lt;/li&gt;
&lt;li&gt;web.py&lt;/li&gt;
&lt;li&gt;CherryPy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Development (Client-Side)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;HTML, CSS, JavaScript - assembly languages&lt;/li&gt;
&lt;li&gt;Haml, Sass, CoffeeScript - 2nd-order languages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Special-Purpose Languages&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Fortran - high-performance numerical programming&lt;/li&gt;
&lt;li&gt;Lua - embedded game programming (ex: game mods, AIs)&lt;/li&gt;
&lt;li&gt;Lisp (Racket) - academic programming&lt;sup&gt;AcadProg&lt;/sup&gt;; dynamic; great for embedded DSLs&lt;/li&gt;
&lt;li&gt;Haskell - academic programming&lt;sup&gt;AcadProg&lt;/sup&gt;; static; better compile-time safety than any mainstream language&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;span style=&quot;font-variant: small-caps;&quot;&gt;AcadProg&lt;/span&gt;: This language tends to be used in academia, especially by programming language researchers. Thus it also gets various cutting-edge programming language features before mainstream languages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related Articles:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2014/12/20/languages-by-hardware-distance/&quot;&gt;Spectrum of Languages by Hardware Distance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/20/visual-guide-to-programming-language-properties/&quot;&gt;Visual Guide to Programming Language Properties&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;programming-paradigms&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Programming Paradigms &lt;small&gt;(Ideas that Change the World)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The following paradigms are presented in chronological order by their recognition in the wider programming community.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;(Ye Olde) Structured Programming (ALGOL)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;ban &lt;code&gt;goto&lt;/code&gt; &amp;ndash; GOTO Considered Harmful&lt;/li&gt;
&lt;li&gt;single entry, single exit&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Declarative Programming (Prolog, SQL, and other DSLs)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Tell me what you want to do and I&amp;rsquo;ll figure out how to actually do it.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object-Oriented Programming (Smalltalk &amp;amp; Java)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Decomposing the behavior of a large system into smart modules that interact with each other through interfaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functional Programming (Lisp &amp;amp; Haskell)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Higher-order functions.&lt;/li&gt;
&lt;li&gt;Building complex data structures out of simple primitive collections (especially lists).&lt;/li&gt;
&lt;li&gt;Constrained side effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;process&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Process&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;collaborative-software-development&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Collaborative Software Development&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Open Source&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Stand on the shoulders of giants. Learn new techniques.&lt;/li&gt;
&lt;li&gt;Work on projects you&amp;rsquo;re passionate about.&lt;/li&gt;
&lt;li&gt;Start your own projects to get free development resources from the community.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version Control Systems&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Centralized (CVS, SVN, Perforce)&lt;/li&gt;
&lt;li&gt;Distributed (Git, Mercurial)&lt;/li&gt;
&lt;li&gt;Patches - create, view, apply, submit&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Build Systems&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;configure, make (C&lt;wbr/&gt;)&lt;/li&gt;
&lt;li&gt;Ant (Java)&lt;/li&gt;
&lt;li&gt;Rake (Ruby)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency Management&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Versioning

&lt;ul&gt;
&lt;li&gt;Semantic Versioning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Package Managers, Environment Isolators&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;code-conventions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Code Conventions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Philosophy&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Clarity is paramount.&lt;/li&gt;
&lt;li&gt;Consistency is a close second.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Indentation&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;2 columns vs. 4 columns&lt;/li&gt;
&lt;li&gt;Tabs vs. spaces&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;80 column lines&lt;/strong&gt; (or max 100)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brace positioning&lt;/strong&gt; (when applicable)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Whitespace around operators&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Method ordering and grouping&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blank lines and paragraphs&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;communicating-software-designs&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Communicating Software Designs &lt;small&gt;(UML &amp;amp; Other Diagrammatic Notations)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Most of the following diagram notations assume the use of object-oriented programming. Non-OO languages do not have any standard diagram types, to my knowledge.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;(Ye Olde) Flow Chart&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Class Diagrams&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Charts&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sequence &amp;amp; Communication Diagrams&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Cases (Fully Dressed)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CRC Cards&lt;/strong&gt; (designing classes with responsibilities in mind)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;detecting-defects-early&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Detecting Defects Early &lt;small&gt;(Testing)&lt;/small&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unit Testing, Code Coverage, Continuous Integration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Static Analysis&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Compiler

&lt;ul&gt;
&lt;li&gt;Strong static typing&lt;/li&gt;
&lt;li&gt;Enabling extra warnings (&lt;code&gt;-Wall&lt;/code&gt;, &lt;code&gt;-Weverything&lt;/code&gt;, &lt;code&gt;-Werror&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lint&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Analysis&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Valgrind&lt;/li&gt;
&lt;li&gt;Fault Injection&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Matrixes, Environment Isolators, Virtual Machines&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Large Hammers&amp;rdquo;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Fuzzing&lt;/li&gt;
&lt;li&gt;Stress Testing&lt;/li&gt;
&lt;li&gt;Longhaul Testing&lt;/li&gt;
&lt;li&gt;(many more)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;improving-code-quality&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Improving Code Quality &lt;small&gt;(Basic Refactoring)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;Transforming the structure of existing code to improve it while maintaining its original behavior is a process called refactoring. Regularly applying refactoring to your code will greatly extend its maintainable life.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rename Method or Variable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extract Method&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Introduce Explaining Variable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replace Magic Number with Symbolic Constant&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replace Nested Conditional with Guard Clauses&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Meta:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplication is the root of all evil.&lt;/li&gt;
&lt;li&gt;Prefer delegation over inheritance.&lt;/li&gt;
&lt;li&gt;Prefer interfaces over abstract classes.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;debugging-techniques&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Debugging Techniques &lt;small&gt;(When It Breaks)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;No program is perfect. Even if one were, requirement changes will break it soon enough.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Print Statements, Logging&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debuggers&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Breakpoints, Catchpoints&lt;/li&gt;
&lt;li&gt;Conditional Breakpoints &amp;amp; Watching variables&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heap Analyzers&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;profiling-instrumentation&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Profiling/Instrumentation &lt;small&gt;(Making It Faster)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;Meta:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Premature optimization is frequently a waste of time.

&lt;ul&gt;
&lt;li&gt;Programmer time is more valuable that machine time.&lt;/li&gt;
&lt;li&gt;Algorithm choice has a larger impact on performance than almost any manual tweaking.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;maintaining-legacy-code-safely&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Maintaining Legacy Code Safely &lt;small&gt;(Advanced Refactoring)&lt;/small&gt;&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Although the concept of refactoring can be applied to any code, not just legacy code, the &lt;/em&gt;deliberate and careful&lt;em&gt; application of refactoring techniques is mostly restricted to legacy code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is covered in great detail in the &amp;ldquo;Refactoring&amp;rdquo; book by Martin Fowler.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;other&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Other&lt;/h2&gt;

&lt;p&gt;The topics in this section don&amp;rsquo;t fit in any of the other major topics. Should these extra topics not form a cohesive whole, they will not be included in the book.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;persistence&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Persistence&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prefer the use of a standard metaformat instead of rolling your own format.&lt;br/&gt;
You&amp;rsquo;ll save a ton of time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standard Metaformats&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;XML&lt;/li&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;li&gt;YAML&lt;/li&gt;
&lt;li&gt;Config files

&lt;ul&gt;
&lt;li&gt;UNIX config file&lt;/li&gt;
&lt;li&gt;Windows INI file&lt;/li&gt;
&lt;li&gt;Mac Plist file&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQLite database&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Considerations with custom formats&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Text vs. Binary&lt;/li&gt;
&lt;li&gt;Backward Compatibility, Forward Compatibility, Version Numbers&lt;/li&gt;
&lt;li&gt;Extensibility&lt;/li&gt;
&lt;li&gt;In-place Modifications &amp;amp; Appendability

&lt;ul&gt;
&lt;li&gt;For text formats, this means the preservation of comments and whitespace.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Partially-loadable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Examples of custom formats&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Hotline protocol - highly extensible, featureful, binary protocol&lt;/li&gt;
&lt;li&gt;Mac resource fork format - partially-loadable appendable binary file format&lt;/li&gt;
&lt;li&gt;QuickTime video container - highly extensible binary file format&lt;/li&gt;
&lt;li&gt;Matroska video container - highly extensible binary file format&lt;/li&gt;
&lt;li&gt;ZIP file format&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bundles&lt;/strong&gt; - a means for combining multiple subfiles into a single virtual file&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;comments&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Comments?&lt;/h2&gt;

&lt;p&gt;Does any of this content sound interesting to you? If so, &lt;a href=&quot;/contact/&quot;&gt;drop me a line&lt;/a&gt;. I may add/remove content and/or modify the order that I write the chapters based on feedback.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;progress&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Progress&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2015-08-08&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Added a section on &lt;a href=&quot;/articles/2015/08/08/algorithms-101/&quot;&gt;Basic Collections&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Retroactively link some articles under &amp;ldquo;Comparing Programming Languages&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2013-07-13&lt;/strong&gt;: Added the &lt;a href=&quot;/articles/2013/07/13/error-handling/&quot;&gt;Error Handling&lt;/a&gt; chapter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2013-06-01&lt;/strong&gt;: Added the &lt;a href=&quot;/articles/2013/06/01/handling-text-correctly/&quot;&gt;Text&lt;/a&gt; chapter.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;For example, the early appearance of the Ruby on Rails web framework in the Ruby language caused a lot of the Ruby ecosystem to cater to web development needs. Subsequently Ruby gained the &amp;ldquo;move fast and break things&amp;rdquo; web mentality, along with the necessary tooling to support that mentality: heavy-duty testing, continuous integration, semantic versioning, package management, etc.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/05/07/avoid-feeling-like-a-port-on-the-mac</id>
   <title>Avoid feeling like a port on the Mac</title>
   <published>2013-05-07T00:00:00+00:00</published>
   <updated>2013-05-07T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/05/07/avoid-feeling-like-a-port-on-the-mac/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Mac users get rather annoyed when using programs that feel like they&amp;rsquo;re just a port from another OS (usually Windows).&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s are a few important points for making your Mac app feel like a native app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The user should never have to refresh local information that an application is viewing. Refresh should happen automatically when needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Exception:&lt;/em&gt; Web browsers. (The HTTP protocol provides no means to detect whether a web page requires refresh while it is being viewed.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Common violation:&lt;/em&gt; Wait for an application to close, without auto-refreshing the application list. [&lt;em&gt;violated by Adobe Flash Updater&lt;/em&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Common violation:&lt;/em&gt; Wait for disk to be inserted, without auto-refreshing the disk list.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When altering settings, change take effect &lt;em&gt;immediately&lt;/em&gt;. If these settings are presented in a dialog, the changes can be reverted by pressing Cancel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Common violation:&lt;/em&gt; Settings dialogs that have an &amp;ldquo;Apply&amp;rdquo; button in addition to &amp;ldquo;OK&amp;rdquo; and &amp;ldquo;Cancel&amp;rdquo;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When dialogs are used to present information, the buttons in the dialog should have titles that are useful and easy to interpret. The default action should be presented as the right-most button.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt; The Log Out action presents a dialog asking the user to confirm whether they want to log out, with buttons &amp;ldquo;Cancel&amp;rdquo; and &amp;ldquo;Log Out&amp;rdquo;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Common violation:&lt;/em&gt; Any dialog with &amp;ldquo;Yes&amp;rdquo;, &amp;ldquo;No&amp;rdquo;, and &amp;ldquo;Cancel&amp;rdquo; buttons.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don&amp;rsquo;t ask the user any information that can be detected automatically with high confidence.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Common violation:&lt;/em&gt; Asking the user what language to use. [&lt;em&gt;Some installers&lt;/em&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Common violation:&lt;/em&gt; Web pages for downloading software that prompt the user to select 32-bit vs. 64-bit architecture or an OS version.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Aesthetics are important. If you make an ugly app, it probably won&amp;rsquo;t be used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag &amp;amp; drop should be supported whenever it seems like it should make sense.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And now for some nitpicks related to command key shortcuts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Common command key shortcuts must be supported and not modified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Command-Shift-Z = Redo [&lt;em&gt;violated by all Microsoft programs&lt;/em&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Command-Left/Right = Move to beginning and end of line [&lt;em&gt;violated by all Microsoft programs&lt;/em&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Command-F = Find [&lt;em&gt;violated by Microsoft Outlook&lt;/em&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Command-P = Print [&lt;em&gt;violated by Sublime Text&lt;/em&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All command key shortcuts must include the command key. That is neither Control nor Option (Alt) can be the primary modifier for a shortcut sequence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not make shortcuts with the function keys (F1 - F15). They are hard to remember.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All command key shortcuts must be tied to a menu item.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt; Command-Option-Escape (Force Quit), which is analogous to Control-Alt-Delete on Windows, can actually be found in the Apple menu.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Exception:&lt;/em&gt; Command-Shift-3 and Command-Shift-4 are legacy shortcuts that take screenshots.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is no such thing as the Apple key. You probably meant the Command key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is no such thing as the Backspace key. You probably meant the Delete key - which is not to be confused with the Forward Delete key, which most Windows users just call Delete.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not all users have a right mouse button. In that case, you must instruct the user to Control-click instead of right-click.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Exemplar:&lt;/em&gt; The game Black and White detects whether the primary mouse is a single-button or a multi-button mouse and provides different instructions (and mouse graphics) for each case.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For all other issues, including other philosphical concerns to consider, read and follow the OS X &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AppleHIGuidelines/Intro/Intro.html&quot;&gt;Human Interface Guidelines&lt;/a&gt;&amp;nbsp;(HIG). This is one of the best descriptions of the &amp;ldquo;Zen of the Mac&amp;rdquo;. Every Mac developer should reread this every few years.&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/04/30/copyrights-and-licenses-for-software</id>
   <title>Copyrights and Licenses for Software</title>
   <published>2013-04-30T00:00:00+00:00</published>
   <updated>2013-04-30T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/04/30/copyrights-and-licenses-for-software/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;This is a quick overview of copyrights and licenses for software developers who may not know their rights under United States law. I cannot speak for international copyright law.&lt;/p&gt;

&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Disclaimer
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        This article presents legal information but does not provide legal advise. Although all information is correct to the best of my knowledge, I will not be held responsible for the consequences of actions you take based on information found to be incorrect or misleading.
    &lt;/p&gt;
&lt;/div&gt;


&lt;h2&gt;Copyrights&lt;/h2&gt;

&lt;p&gt;The first time that a piece of software is published, whether it be in binary or source form, it automatically gains copyright status. This is true even if you don&amp;rsquo;t include the magic words &lt;code&gt;Copyright (c) 2013 David Foster&lt;/code&gt;.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;Copyright grants the author certain exclusive rights.&lt;/h3&gt;

&lt;p&gt;That is, other people don&amp;rsquo;t get these rights. Such rights include (but are not limited to):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The right to &lt;em&gt;distribute&lt;/em&gt; the software, even for free.&lt;/li&gt;
&lt;li&gt;The right to &lt;em&gt;sell&lt;/em&gt; the software.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;But then you might ask how download sites like Download.com can operate: If by default only the original author has the right to distribute the software they create, a download site would need to get special permission (i.e. a &lt;em&gt;license&lt;/em&gt;) to distribute most programs on their site, which would be time consuming (and therefore expensive).&lt;/p&gt;

&lt;p&gt;In reality, download sites generally rely on software authors to not &lt;em&gt;enforce&lt;/em&gt; their copyrights. Which brings us to another point:&lt;/p&gt;

&lt;h3&gt;Copyrights are useless unless they are enforced.&lt;/h3&gt;

&lt;p&gt;Enforcement takes the form of the copyright holder actively looking for &lt;em&gt;infringers&lt;/em&gt;: other people who are distributing or selling the software without permission.&lt;/p&gt;

&lt;p&gt;For example, the MPAA may issue a DMCA takedown request to a YouTube user who has (without permission) posted an episode of a TV show that MPAA owns. If the user does not comply with the takedown, the MPAA may sue the user for infringement.&lt;/p&gt;

&lt;h2&gt;Licenses&lt;/h2&gt;

&lt;h3&gt;A copyright holder may waive or share some rights by issuing a &lt;em&gt;license&lt;/em&gt;.&lt;/h3&gt;

&lt;p&gt;Licenses may be issued to individuals or companies. For example  a particular distributor may be granted the right to market and sell the software on behalf of the original developer.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;For open source software, licenses are typically granted to the community as a whole (i.e. every recipient of the program). This is typically done by including a file called &lt;code&gt;LICENSE&lt;/code&gt; or &lt;code&gt;COPYING&lt;/code&gt; with the software. A license may also be found in the software&amp;rsquo;s &lt;code&gt;README&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can write your own custom license (if you feel comfortable writing in legalese). Or you can use one of the more common existing licenses from the community. (See &lt;a href=&quot;#common_licenses&quot;&gt;Common Licenses&lt;/a&gt; below for a list.)&lt;/p&gt;

&lt;h3&gt;Dual Licensing&lt;/h3&gt;

&lt;p&gt;Sometimes the same piece of software is offered under multiple licenses.&lt;/p&gt;

&lt;p&gt;For example the Qt GUI toolkit has been available under both the GPL license and (with payment) a commercial closed-source license for a long time. Since companies don&amp;rsquo;t like basing their own closed source software on GPL-licensed original software, this gives them an option to use a more corporate-friendly commercial license.&lt;/p&gt;

&lt;p&gt;When creating a new piece of software that is based on or uses dual-licensed software, you should document which license the original software is being used under.&lt;/p&gt;

&lt;p&gt;If you are the original author of a piece of software, you can issue a new version of the software under additional licenses.&lt;/p&gt;

&lt;h3&gt;Changing a Software&amp;rsquo;s License&lt;/h3&gt;

&lt;p&gt;Under rare circumstances, the license provided with software can change.&lt;/p&gt;

&lt;p&gt;As the copyright holder of a piece of software, you may decide to release a new version with a different set of licenses than prior versions. For example you could change the license offered from &lt;a href=&quot;#bsd&quot;&gt;BSD&lt;/a&gt; to &lt;a href=&quot;#gpl&quot;&gt;GPL&lt;/a&gt;, a rather radical change. Such a change would only be in effect for the newly released version - it would have no effect on older released versions.&lt;/p&gt;

&lt;p&gt;If you are not the copyright holder of a piece of software, you cannot change the license(s) under which it is offered.&lt;/p&gt;

&lt;p&gt;If there are contributors beyond the original author whose changes have been incorporated into the software, they become partial copyright holders in the software as well unless they explicitly waive their copyright interests via a Contributor Agreeement or similar document. In the event of multiple copyright holders, all holders must agree to any proposed changes in the set of licenses under which the software is offered. Since there may be a large number of contributors (and thus copyright holders), it may be impossible to get permission from everyone, thereby making a license change infeasible.&lt;/p&gt;

&lt;p&gt;Projects that are particularly aware of copyright concerns may require all contributors to sign a Contributor Agreement that either waives all copyright interests or explicitly assigns the copyright associated with all contributions to the original author.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;No Warranty&lt;/h3&gt;

&lt;p&gt;All software licenses I have seen explicitly disclaim all warranties. Meaning that if the software harms someone, you can&amp;rsquo;t sue the developer for it. This is great for software developers but in my opinion bad for society.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;common_licenses&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Common Licenses&lt;/h3&gt;

&lt;p&gt;Here are the most common open source licenses, arranged generally from most permissive to most restrictive.&lt;/p&gt;

&lt;p&gt;If you don&amp;rsquo;t care about the details and only want to know when to use which license, skip to the &lt;a href=&quot;#license_summary&quot;&gt;summary&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;mit&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Public Domain&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;small&gt;&amp;mdash; ultimately permissive&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Do whatever you want with this software.&lt;/li&gt;
&lt;li&gt;This software cannot ever be placed under copyright or any license.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;mit&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;MIT License &lt;small&gt;&amp;mdash; super permissive, simple&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Do whatever you want with this software.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;bsd&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;BSD License &lt;small&gt;&amp;mdash; permissive, simple&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can redistribute this software.&lt;/li&gt;
&lt;li&gt;(Other rights are not expressedly waived.)&lt;/li&gt;
&lt;li&gt;There are several &lt;a href=&quot;http://en.wikipedia.org/w/index.php?title=BSD_licenses&amp;amp;oldid=539421860&quot;&gt;variants&lt;/a&gt; of this license.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;apache&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Apache 2.0 License &lt;small&gt;&amp;mdash; permissive, complex&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can do anything normally restricted by copyright.&lt;/li&gt;
&lt;li&gt;You can do anything normally restricted by patent rights.&lt;/li&gt;
&lt;li&gt;Redistribution must be done under certain terms.&lt;/li&gt;
&lt;li&gt;Submissions by contributors automatically fall under
this license unless specified otherwise.&lt;/li&gt;
&lt;li&gt;You may NOT use trademarks related to this software
(except in a few special cases).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;lgpl&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;LGPL License 2.1 &lt;small&gt;&amp;mdash; restrictive, complex&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can redistribute this software.&lt;/li&gt;
&lt;li&gt;You can modify this software and distribute the derived work. However the derived work must also be LGPL-licensed.&lt;/li&gt;
&lt;li&gt;You can relicense a copy of this software under the GPL. (This is an irreversible action for works derived from the new copy.)&lt;/li&gt;
&lt;li&gt;If you create your own software that uses this LGPL-software, the license of your source code is unaffected. However the resulting &lt;em&gt;executable&lt;/em&gt; and (sometimes) the &lt;em&gt;object code&lt;/em&gt; must satisfy the following terms:

&lt;ul&gt;
&lt;li&gt;Modification of the executable and object code is permitted for personal use.&lt;/li&gt;
&lt;li&gt;Reverse engineering of the executable and object code is permitted.&lt;/li&gt;
&lt;li&gt;You must give notice that the executable and object code uses this software and that this software is licensed under the LGPL. You must also provide a copy of the LGPL license text.&lt;/li&gt;
&lt;li&gt;If the software displays copyright notices during its operation (such as in an About box), the LGPL copyright notice for this software must be included and a reference to the full LGPL license text must be provided.&lt;/li&gt;
&lt;li&gt;Either:

&lt;ul&gt;
&lt;li&gt;(1) Include the source code for this software (including any modifications you made to it) when distributing the executable and object code.&lt;/li&gt;
&lt;li&gt;(2) Require that the user of the executable or object code have this software installed locally already, and use shared library mechanisms to link the executable against the (unmodified) local copy of this software.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If distributing an executable, the nondistributed form of your software must include any data or utility programs necessary to compile the executable.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;gpl&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;GPL License 2.0 &lt;small&gt;&amp;mdash; restrictive, complex, &amp;ldquo;viral&amp;rdquo;&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can redistribute the source code of this software.&lt;/li&gt;
&lt;li&gt;You can modify this software and distribute the derived work.  However the derived work must also be GPL-licensed.&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;You can distribute this software or any software you create based on it, in executable or object code form, provided that you also distribute the corresponding source code (or provide a written offer to do so).&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;No License &lt;small&gt;&amp;mdash; ultimately restrictive&lt;/small&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You cannot redistribute or sell this software.&lt;/li&gt;
&lt;li&gt;You cannot create new software that is based on this software (i.e. derivative works).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a name=&quot;license_summary&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Choosing a License&lt;/h3&gt;

&lt;p&gt;It is best to pick the license whose terms convey the message you want to send:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Public Domain&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Do anything you want with this software. It is free forever.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MIT&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Do anything you want with this software. (Although I might change my mind later.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BSD (4-clause)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Do anything you want with this software, although I want to be attributed (i.e. mentioned as the original author). But I don&amp;rsquo;t want my name used to promote other things.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apache&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You can do most things with this software.&lt;br/&gt;
(And my lawyers want a precise definition of what &amp;ldquo;most things&amp;rdquo; means.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LGPL&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I want the source code for this software library (and any derived software) to be freely available forever. I also want to enforce that all improvements to this software library that are incorporated into other products be available for independent inspection.&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t care if these extra terms made it burdensome for commercial entities to use my library, although I would like to make it possible for them to still use it if desired.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPL&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I want the source code for this software library and any external software that uses it to be freely available forever.&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t care if this means that my software will never be incorporated into a commercial product.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copyright Notice; No License&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t even think about incorporating this software into another product, or selling it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Copyright Notice; No License&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I don&amp;rsquo;t know about copyright or licenses. Ask me if you want to do something with my software.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Now that I&amp;rsquo;ve figured all of this out, it&amp;rsquo;s time to update the licenses I&amp;rsquo;m using for &lt;a href=&quot;https://github.com/davidfstr?tab=repositories&quot;&gt;my own open source projects&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;However if you &lt;em&gt;do&lt;/em&gt; include the magic words &lt;code&gt;Copyright (c) 2013 David Foster&lt;/code&gt; it is easier to demonstrate &lt;em&gt;willful&lt;/em&gt; infringement when you sue someone for infringing your copyright. Willful infringment entitles the copyright owner to higher &lt;em&gt;damages&lt;/em&gt; (i.e. payments from the infringer) than vanilla infringement.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;If you sell any apps on the App Store, you signed an agreement giving Apple such marketing rights.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;For example my present company Splunk requires that all contributors to its open source projects sign a Contributor Agreement of this type.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;Technically the state of being in the &amp;ldquo;public domain&amp;rdquo; is not a license. Any work explicitly released into the public domain is not subject to copyright law at all. In particular there is no copyright holder and can never be a copyright holder in the future.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;At face value this doesn&amp;rsquo;t actually seem like a restriction. However the LGPL text cautions, &amp;ldquo;It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.&amp;rdquo;&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;The GPL is ambiguous with respect to whether a piece of software that you create based on the GPL-licensed software (including merely linking to it) should be considered a derivative work or not. If so, then the GPL is truly &amp;ldquo;viral&amp;rdquo;: any piece of code that interfaces with GPL-licensed software must also be licensed under the GPL. If not, the GPL still specifies unambiguously that programs based on GPL-licensed software must be distributed with all accompanying source code. Neither proposition is tolerable for most corporate software entities.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/04/09/making-an-existing-python-program-unicode-aware</id>
   <title>Making an Existing Python Program Unicode Aware</title>
   <published>2013-04-09T00:00:00+00:00</published>
   <updated>2013-04-09T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/04/09/making-an-existing-python-program-unicode-aware/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Last week I decided to update one of my larger Python 2.7 projects to support Unicode fully
and to run under Python 3.&lt;/p&gt;

&lt;p&gt;Here are the steps that I took and some gotchas I ran into along the way.&lt;/p&gt;

&lt;h2&gt;General Strategy&lt;/h2&gt;

&lt;p&gt;Create and fully automate the unit test suite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is important to detect any unexpected breakage from the Unicode-related changes you&amp;rsquo;ll be making soon.&lt;/li&gt;
&lt;li&gt;Make sure your code coverage is good since tests can&amp;rsquo;t protect you from mistakes introduced in uncovered code.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Identify all boundaries where data is being exchanged between the program and the outside environment. In my case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct I/O (i.e. &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Filesystem access (i.e. &lt;code&gt;open&lt;/code&gt; and file paths)&lt;/li&gt;
&lt;li&gt;Process manipulation (via the &lt;code&gt;subprocess&lt;/code&gt; module)&lt;/li&gt;
&lt;li&gt;Command-line arguments (via &lt;code&gt;sys.argv&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Time access (via the &lt;code&gt;time&lt;/code&gt; module)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;At boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads should decode bytestrings to unicode using the proper encoding. You may need to do research to determine what the correct encoding is or how to determine the correct encoding at runtime.

&lt;ul&gt;
&lt;li&gt;Since my program did a lot of direct I/O on classic Mac OS data structures, the correct encoding was typically MacRoman.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.getfilesystemencoding()&lt;/code&gt; is sometimes appropriate. Be sure to test on Windows, where this value is typically not UTF-8.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Writes should encode unicode (or ASCII bytestring literals) to bytestrings using the proper encoding.&lt;/li&gt;
&lt;li&gt;Ensure files and streams explicitly use either binary mode (i.e. &lt;code&gt;rb&lt;/code&gt; or &lt;code&gt;wb&lt;/code&gt;) or text mode (i.e. &lt;code&gt;rt&lt;/code&gt; or &lt;code&gt;wt&lt;/code&gt;).

&lt;ul&gt;
&lt;li&gt;UsuBytesIOally you want binary mode.&lt;/li&gt;
&lt;li&gt;Text mode is required for certain cases, such as the output of the &lt;code&gt;json&lt;/code&gt; module. Even then, it&amp;rsquo;s a good idea to restrict text-based output to the ASCII character set since the native text encoding may not support the full Unicode set, particularly on Windows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Finally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the &lt;code&gt;2to3&lt;/code&gt; converter on your program so that it can be run by Python 3.&lt;/li&gt;
&lt;li&gt;Run your new Python 3 source code in a Python 3 interpreter, perhaps inside a fresh Linux VM.&lt;/li&gt;
&lt;li&gt;Run your test suite under the Python 3 interpreter. It should find any Unicode mistakes that still need to be fixed.&lt;/li&gt;
&lt;li&gt;You will probably need to repeat this convert-test-fix cycle a couple of times.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Special Cases&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Most uses of &lt;code&gt;StringIO&lt;/code&gt; need to be migrated to &lt;code&gt;BytesIO&lt;/code&gt;, when used as a byte buffer. If used as a string buffer, the &lt;code&gt;StringIO&lt;/code&gt; uses need to be left at &lt;code&gt;StringIO&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Here&amp;rsquo;s the shim I used to support &lt;code&gt;BytesIO&lt;/code&gt; and &lt;code&gt;StringIO&lt;/code&gt; in both Python 2 and 3. I put it in a utility module and the rest of the program imports the shims instead of using the standard library.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;
# BytesIO presents a stream interface to an in-memory bytestring.
# 
# This is equivalent to StringIO in Python 2 and to BytesIO in Python 3.
try:
    from io import BytesIO              # Python 3
except ImportError:
    from StringIO import StringIO as BytesIO

# StringIO presents a stream interface to an in-memory string
# (which is a bytestring in Python 2 and a unicode string in Python 3).
# 
# This is equivalent to StringIO in both Python 2 and 3.
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO             # Python 3
&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;When writing to a binary stream, replace uses of &lt;code&gt;output.write(chr(byte_ordinal))&lt;/code&gt; with &lt;code&gt;output.write(bchr(byte_ordinal))&lt;/code&gt; and use the following shim for &lt;code&gt;bchr&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;
# bchr() converts the specified byte integer value to a single character
# bytestring.
# 
# This is equivalent to chr() in Python 2 but requires special handling in
# Python 3.
if bytes == str:
    def bchr(byte_ordinal):
        return chr(byte_ordinal)
else:
    def bchr(byte_ordinal):
        return bytes([byte_ordinal])    # Python 3
&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;Beware of comparisons with &lt;code&gt;''&lt;/code&gt;. Some of them probably need to be converted to comparisons with &lt;code&gt;b''&lt;/code&gt;. For example, I had to adjust my &lt;code&gt;at_eof&lt;/code&gt; utility function:&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;
def at_eof(input):
    &quot;&quot;&quot;
    Returns whether the specified input stream is at EOF.
    &quot;&quot;&quot;
    with save_stream_position(input):
        at_eof = input.read(1) == b''
    return at_eof
&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;If your program uses human-readable ASCII bytestring literals, such as FourCC codes, make sure they are marked with the &lt;code&gt;b&lt;/code&gt; prefix appropriately.&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;
if type_code == b'APPL':
&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;Iteration over bytestrings works differently in Python 2 vs Python 3.

&lt;ul&gt;
&lt;li&gt;The code &lt;code&gt;for c in data:&lt;/code&gt; will give back single-character bytestrings in Python 2 but byte ordinals in Python 3.&lt;/li&gt;
&lt;li&gt;Here&amp;rsquo;s my shim to let &lt;code&gt;for b in iterord(data):&lt;/code&gt; always iterate over byte ordinals:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;
# iterord() iterates over the integer values of the bytes in the specified
# bytestring.
if bytes == str:
    def iterord(bytes_value):           # Python 2
        for b in bytes_value:
            yield ord(b)
else:
    def iterord(bytes_value):           # Python 3
        return bytes_value
&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;&lt;code&gt;time.strftime&lt;/code&gt; returns a bytestring in Python 2 and a Unicode string in Python 3. Usually you want a Unicode string. I didn&amp;rsquo;t create a shim for this since I only had one use of &lt;code&gt;strftime&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;
now_string = time.strftime('%b %d %H:%M', time.localtime(now))
if not isinstance(now_string, unicode):
    now_string = now_string.decode('ascii')
&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Regular expressions that are intended to apply to bytestrings instead of Unicode strings may need updating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For example the pattern &lt;code&gt;re.compile(r'^Volume name is &quot;(.*)&quot;$')&lt;/code&gt; which is designed to be applied to a MacRoman-encoded bytestring would need to be updated to read &lt;code&gt;re.compile(br'^Volume name is &quot;(.*)&quot;$')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don&amp;rsquo;t forget to update your documentation to specify where Unicode (or ASCII bytestring literals) are expected.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/04/07/beautiful-code-sqlite</id>
   <title>Beautiful Code: SQLite</title>
   <published>2013-04-07T00:00:00+00:00</published>
   <updated>2013-04-07T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/04/07/beautiful-code-sqlite/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;It has been said that you can learn a lot from reading other people&amp;rsquo;s high-quality software. So I gave it a try this weekend by reading the SQLite source.&lt;/p&gt;

&lt;p&gt;SQLite is a lightweight embedded database that does not require a standalone server. It is designed to be reliable, highly portable, and require minimal administration.&lt;/p&gt;

&lt;p&gt;SQLite has some of the &lt;a href=&quot;https://www.sqlite.org/testing.html&quot;&gt;most rigorous testing methodology&lt;/a&gt; I have seen in an open source project. Thus its true defect count is likely to be extremely low, making it high quality.&lt;/p&gt;

&lt;p&gt;Such a high quality product probably contains useful patterns and techniques, some of which I could reuse in my own programs. So I decided to dive into the SQLite source and see what gems I could pull out. Here are my notes:&lt;/p&gt;

&lt;h2&gt;Architecture &amp;amp; Design&lt;/h2&gt;

&lt;p&gt;I started by reading the high-level design documentation. SQLite has exceptionally good documentation of this type.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.sqlite.org/docs.html&quot;&gt;Documentation Index&lt;/a&gt; - &lt;em&gt;Root of all documentation.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.sqlite.org/arch.html&quot;&gt;Architecture Documentation&lt;/a&gt; - &lt;em&gt;Excellent overview of the architecture.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Query Planner Documentation - &lt;em&gt;Describes how prepared statements are executed.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sqlite.org/vdbe.html&quot;&gt;The Virtual Database Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sqlite.org/opcode.html&quot;&gt;Virtual Machine Opcodes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Internal Tools of Note&lt;/h3&gt;

&lt;h4&gt;&lt;a href=&quot;http://www.fossil-scm.org/index.html/doc/trunk/www/index.wiki&quot;&gt;Fossil&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Distributed version control system used by SQLite. I&amp;rsquo;ve never heard of this. Beyond version control also provides bug tracking, a wiki, and a blog.&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;http://www.sqlite.org/src/doc/trunk/doc/lemon.html&quot;&gt;Lemon&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;A custom parser generator used by SQLite. Alternative to the old bison/yacc combination which has some improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Syntax that is less error-prone.&lt;/li&gt;
&lt;li&gt;Fast. Reentrant. Thread-safe.&lt;/li&gt;
&lt;li&gt;Easier to write parsers that avoid leaking memory upon error conditions.

&lt;ul&gt;
&lt;li&gt;Important since SQLite is serious about handling out of memory conditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;&lt;a href=&quot;http://www.sqlite.org/vfs.html&quot;&gt;VFS&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;OS abstraction layer. Despite the acronym (Virtual Filesystem), it is more than just filesystem manipulation routines.&lt;/p&gt;

&lt;h2&gt;Implementation Notes&lt;/h2&gt;

&lt;h3&gt;table.c (sqlite3_get_table)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This is the main entry point into the SQLite API.
It executes a SQL statement and returns the result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;First impression is that most methods have a lot of malloc-failed handling. And indeed if you read the testing procedures, they involve causing random malloc errors throughout the code, so there has to be handling for such errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hungarion notation is used as well. Ick. But at least it is consistent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;z = string&lt;/li&gt;
&lt;li&gt;a = array&lt;/li&gt;
&lt;li&gt;p = object pointer&lt;/li&gt;
&lt;li&gt;n = int&lt;/li&gt;
&lt;li&gt;x = function pointer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/* Assume 32-bit assignment is atomic */&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interesting that such a property would be &lt;em&gt;consciously&lt;/em&gt; relied on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;legacy.c (sqlite3_exec)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This is the legacy entry point into the SQLite API.
It still exists and is actually used internally by the currently
recommended API entry point (&lt;code&gt;sqlite3_get_table&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are some odd syntactic conventions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-line comments use double-stars to prefix middle lines.&lt;/li&gt;
&lt;li&gt;No space before closing &lt;code&gt;{&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Spaces inside outer parentheses for most statements
(&lt;code&gt;if&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;assert&lt;/code&gt;) but not all (&lt;code&gt;for&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It appears that functions that begin with &lt;code&gt;sqlite3_&lt;/code&gt; are public,
whereas functions starting with &lt;code&gt;sqlite3&lt;/code&gt; (no underscore) are private.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;vdbeapi.c (sqlite3_step)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This function executes one or more instructions from the instruction list
inside of a prepared SQL statement. The instruction is executed inside
of the SQLite virtual database engine (VDBE), which is a virtual machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has a lot of support code for EXPLAIN and profiling callbacks.&lt;/li&gt;
&lt;li&gt;The meat of instruction execution is done by &lt;code&gt;sqlite3VdbeExec&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contains own mutex implementation. (&lt;code&gt;sqlite3_mutex_enter&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deals with a somewhat crazy circumstance: If the database schema changes
in the middle of executing a (prepared) SQL statement, the statement is
reprepared and rerun automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generally there is good commenting for weird and backward-compatibility
behaviors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Practically every function can fail. They all return an integer error code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some functions that operate on an in-out data structure will
additionally store an error code (and message) in that structure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;vdbe.c (sqlite3VdbeExec)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This function executes as many instructions as possible from a prepared
SQL statement. It contains the monsterous switch statement that
enumerates every possible opcode that can be executed.

&lt;ul&gt;
&lt;li&gt;Related reference documentation: &lt;a href=&quot;http://www.sqlite.org/opcode.html&quot;&gt;Virtual Machine Opcodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Related guide documentation: &lt;a href=&quot;http://www.sqlite.org/vdbe.html&quot;&gt;The Virtual Database Engine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Future&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If I were to continue reading into the implementation,
I think the opcodes that manipulate B-trees would likely be
the most interesting ones to look at.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;This is a very high-quality C library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal commenting is good.&lt;/li&gt;
&lt;li&gt;Consistent syntax is used, despite being a bit odd IMHO.&lt;/li&gt;
&lt;li&gt;The guide-level documentation is wonderful.&lt;/li&gt;
&lt;li&gt;Error handling is air-tight and enforced by crazy amounts of test code.&lt;/li&gt;
&lt;li&gt;The architecture provides good separation of roles and is easy to understand.&lt;/li&gt;
&lt;li&gt;Once again, the documentation is excellent.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And its design requirements show through in the implementation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliable&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is more than 1000 times as much test code as there is product code.&lt;/li&gt;
&lt;li&gt;100% branch coverage. That&amp;rsquo;s insanely good.&lt;/li&gt;
&lt;li&gt;Very crazy error classes such as out of memory errors, crashes, integer overflow are all considered and tested for.

&lt;ul&gt;
&lt;li&gt;Malloc checks are prevalent and handled.&lt;/li&gt;
&lt;li&gt;Transactions, journaling, and related testing deal with crashes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;strong&gt;Portable&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The chosen language is C, which is highly portable when written in the appropriate style.&lt;/li&gt;
&lt;li&gt;The so-called VFS layer provides an OS abstraction. Thus porting to an OS mainly just involves writing a new implementation of this abstraction.&lt;/li&gt;
&lt;li&gt;All C files are combined into one giant C file before being sent to the compiler, which provides for better compile-time optimizations for dumber C compilers, which may occur on embedded systems.&lt;/li&gt;
&lt;li&gt;The database format does not depend on endianness or native data type sizes, making it suitable for cross-platform use.&lt;/li&gt;
&lt;li&gt;Very low memory configurations are available, making SQLite suitable for use on embedded devices such as cellphones.&lt;/li&gt;
&lt;li&gt;The code is in the public domain, which removes any licensing barriers.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;strong&gt;Simple&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite is embedded into the program that uses it, requiring no separate server. And no administration for such a server.&lt;/li&gt;
&lt;li&gt;Minimal schema is imposed by SQLite, distinguishing only between integers, reals, text, and blobs at a low level. And even so, a column&amp;rsquo;s type is advisory only - you can store a value of any type in any column (except an &lt;code&gt;INTEGER PRIMARY KEY&lt;/code&gt; column).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Of course being simple sacrifices certain other properties such as high concurrency and the ability to perform fine-grained access control (which requires administrability).&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/03/22/migrating-from-bbedit-to-sublime-text</id>
   <title>Migrating from BBEdit to Sublime Text</title>
   <published>2013-03-22T00:00:00+00:00</published>
   <updated>2013-05-07T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Productivity"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/03/22/migrating-from-bbedit-to-sublime-text/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I&amp;rsquo;ve been using &lt;a href=&quot;http://www.barebones.com/products/bbedit/index.html&quot;&gt;BBEdit&lt;/a&gt; as my primary text editor on the Mac for over 10 years. It is an extremely capable and mature editor with just about all the bells and whistles you can imagine. However the use of Sublime Text has been spreading throughout my workplace at Splunk&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; so I decided I&amp;rsquo;d give it a try.&lt;/p&gt;

&lt;p&gt;My initial impression was &amp;ldquo;BBEdit can do everything that Sublime can, what&amp;rsquo;s the deal?&amp;rdquo; But after using Sublime full-time for about a week, I&amp;rsquo;m starting to come around to it.&lt;/p&gt;

&lt;p&gt;Although it is true that both have comparable feature sets, Sublime&amp;rsquo;s implementation feels more polished - not just eyecandy, but actually better usability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incremental find

&lt;ul&gt;
&lt;li&gt;As you start typing the substring you want to find, it automatically starts searching within the current document. Frequently you don&amp;rsquo;t have to finish typing the substring in order to get the result you want.&lt;/li&gt;
&lt;li&gt;This saves a surprising amount of time compared to BBEdit where you have to finish providing a full substring (that you think is long enough) before kicking off the search.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edit:&lt;/strong&gt; &lt;em&gt;This is actually available in BBEdit under the &amp;ldquo;Live Search&amp;rdquo; command, but this is not part of the default Find experience and not advertised.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;View a file without &amp;ldquo;opening&amp;rdquo; it (as a persistent tab)

&lt;ul&gt;
&lt;li&gt;Sublime keeps files of current interest available as tabs in the main window. If you just click on a file, it is shown in the editor but no tab is created by default. If you decide this is an important file, you can double-click on the file name to create an actual tab for it, which makes the file easy to return to.

&lt;ul&gt;
&lt;li&gt;Most &amp;ldquo;Goto X&amp;rdquo; actions in Sublime both show a file and create an actual tab for it, which usually is what you want.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you click on any file at all in BBEdit, it is &amp;ldquo;opened&amp;rdquo; and added to the &amp;ldquo;Currently Open Documents&amp;rdquo; section, which is analogous to Sublime&amp;rsquo;s set of open tabs. This can result in the &amp;ldquo;Currently Open Documents&amp;rdquo; section getting rather cluttered when rummaging around for a particular document, making it less useful.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Minidocument view on the right side of an open file.

&lt;ul&gt;
&lt;li&gt;This makes it easier to get a bird&amp;rsquo;s eye view of where you are in a long function or file.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Additionally, Sublime&amp;rsquo;s marketing has some a much better job of exposing advanced features that turn out to be useful in daily use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Goto Anything&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;BBEdit has similar &amp;ldquo;Open File by Name&amp;rdquo;, but it&amp;rsquo;s slower, doesn&amp;rsquo;t have as expressive syntax, and isn&amp;rsquo;t incremental.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Open Folder&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;This is equivalent to a BBEdit project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Plugins!

&lt;ul&gt;
&lt;li&gt;This is barely advertised on the BBEdit side but hugely promoted on the Sublime side. Thus lots of people are writing (publicly available) plugins for Sublime but not so many for BBEdit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Some features in Sublime are named more obviously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Convert Indentation to Spaces. Convert Indentation to Tabs.

&lt;ul&gt;
&lt;li&gt;BBEdit calls these operations &amp;ldquo;Detab&amp;rdquo; and &amp;ldquo;Entab&amp;rdquo; respectively.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Some features in Sublime are easier to access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the displayed tab width.

&lt;ul&gt;
&lt;li&gt;To change this for a single file in BBEdit, you have to go to &amp;ldquo;Show Fonts&amp;rdquo;, which I find completely nonintuitive.&lt;/li&gt;
&lt;li&gt;BBEdit also allows you to change the default tab spacing &lt;em&gt;per source language&lt;/em&gt; in its preferences, which makes sense given that different languages have different conventions.&lt;/li&gt;
&lt;li&gt;However BBEdit does not permit you to change the tab width on a per project/folder basis, which is usually what you want when working on someone else&amp;rsquo;s open source project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Access the function list. (&amp;ldquo;Goto Symbol&amp;hellip;&amp;rdquo;)

&lt;ul&gt;
&lt;li&gt;This can be done in Sublime entirely through the keyboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Sublime also has a few features lacking in BBEdit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-platform support

&lt;ul&gt;
&lt;li&gt;This is huge when working in a mixed OS environment. You can use the same editor everywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;BBEdit still is better in a few areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-file search and replace can be done without confirming (or saving) each modified file.&lt;/li&gt;
&lt;li&gt;Robust on slow filesystems, particularly network filesystems.

&lt;ul&gt;
&lt;li&gt;Sublime (2.0.1) acts very poorly: times out on directory listings, silently fails searches in &amp;ldquo;Goto Anything&amp;rdquo;, and probably has other issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Can edit preferences in a GUI without mucking about in text files.&lt;/li&gt;
&lt;li&gt;Can quickly split a single file vertically to edit distant sections simultaneously.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Zap Gremlins&amp;hellip;&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;Deletes or replaces ASCII control characters and other nasties. Very useful for text pasted from web browsers, Word, or other less-than-pure sources of text.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Process Duplicate Lines&amp;hellip;&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;Eliminate duplicate lines in a file. This is often useful after performing a series of text transformations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Process Lines Containing&amp;hellip;&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;Delete (or preserve) all lines containing a subexpression. Exactly like the &lt;code&gt;grep&lt;/code&gt; command-line tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Can edit files on an FTP/SFTP server directly.&lt;/li&gt;
&lt;li&gt;Customer support I&amp;rsquo;ve heard is top-notch.&lt;/li&gt;
&lt;li&gt;It can print.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I think I&amp;rsquo;m going to continue using Sublime Text. Featurewise it&amp;rsquo;s about the same as BBEdit, but the cross-platform support&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, active plugin community, and general polish &lt;!-- &amp; attention to usability --&gt; are winning me over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May 2013 Update:&lt;/strong&gt; I have now switched to Sublime for my daily programming tasks. Its superior &amp;ldquo;Goto Anything&amp;rdquo; functionality is a killer feature for navigating around large projects. And its cross-platform nature is killer when operating in a mixed OS environment. Occasionally I still need to pull out BBEdit to do a large multi-file search &amp;amp; replace, but otherwise I don&amp;rsquo;t use it that frequently.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Splunk makes tools for analyzing large time-series datasets, such as log files. For details see the 3 minute &lt;a href=&quot;http://www.splunk.com/view/SP-CAAAHG6&quot;&gt;Splunk Product Overview&lt;/a&gt;. I work on the Developer Platform, making it easy for other developers to build neat things on top of the Splunk core.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;It is extremely useful to be able to use the same full-featured text editor on any platform I use. I currently maintain a few open source projects that require testing, debugging, and development on multiple platforms (notably the &lt;a href=&quot;/projects/rdiscount/&quot;&gt;RDiscount&lt;/a&gt; Markdown processor) and it&amp;rsquo;s nice being able to use the same editor everywhere.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/03/16/introducing-p4status-a-status-command-for-perforce</id>
   <title>Introducing p4status: A status command for Perforce</title>
   <published>2013-03-16T00:00:00+00:00</published>
   <updated>2013-03-16T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/03/16/introducing-p4status-a-status-command-for-perforce/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;strong&gt;p4status&lt;/strong&gt; works like &lt;code&gt;git status&lt;/code&gt; (or &lt;code&gt;svn status&lt;/code&gt;), but works in Perforce.&lt;/p&gt;

&lt;p&gt;It will list changelist files and locally modified files that haven&amp;rsquo;t been added to any changelist (including unadded files) in a readable format.&lt;/p&gt;

&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Note
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        The 2012 version of Perforce has an official
        &lt;b&gt;p4 status&lt;/b&gt; command. However this command is only available if 
        your corporate Perforce server has been upgraded to 2012. If your 
        company, like mine, has not upgraded their server, this script will 
        make your life easier.
    &lt;/p&gt;
&lt;/div&gt;


&lt;h3&gt;Example&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;[dfoster ~/dev/p4/mybranch/path/to/myproject]$ p4status
# On changelist 154055
# 
# Changes to be committed in changelist default:
#   (use &quot;p4 revert &amp;lt;file&amp;gt;...&quot; to discard changes in working directory)
# 
#       deleted:    server/apps/setupfx/splunkd/default/extract.conf
# 
# Changes to be committed in changelist 154076:
#   (use &quot;p4 revert &amp;lt;file&amp;gt;...&quot; to discard changes in working directory)
# 
#       new file:   server/apps/setupfx/splunkd/default/inputs-NEW.conf
#       modified:   server/apps/setupfx/splunkd/default/inputs.conf
# 
# Changes not staged for commit:
#   (use &quot;p4 add/edit/delete &amp;lt;file&amp;gt;...&quot; to update what will be committed)
#   (use &quot;p4 sync -f &amp;lt;file&amp;gt;...&quot; to discard changes in working directory)
# 
#       new file:   server/apps/setupfx/splunkd/default/inputs-NEW2.conf
# 
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Installation&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Download to your local &lt;code&gt;bin&lt;/code&gt; directory:
&lt;a href=&quot;https://github.com/davidfstr/dotfiles/blob/master/bin/p4status&quot;&gt;https://github.com/davidfstr/dotfiles/blob/master/bin/p4status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mark as executable with &lt;code&gt;chmod a+x p4status&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Usage&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; to the primary directory that you&amp;rsquo;ll be working under.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;p4status&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Limitations&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Only detects unstaged files under the directory in which the command is run. Therefore it is best to reserve a terminal window that is &lt;code&gt;cd&lt;/code&gt;-ed to the correct place where this command can be run safely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This command is too slow to run from the root of very large branches.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Alternatives&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the excellent Git-to-Perforce bridge, &lt;a href=&quot;http://git-scm.com/docs/git-p4&quot;&gt;git-p4&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;This allows you to work with your Perforce repository as if it were a Git repository. And you can use Git&amp;rsquo;s very fast &lt;code&gt;git status&lt;/code&gt; command.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Convince your Perforce server administrator to upgrade to the 2012 version. This may take some time, depending on the size of your company.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Projects&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfstr/dotfiles&quot;&gt;dotfiles&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;My command-line shortcuts, including several for working with Git, particularly in an OS X environment.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/03/10/killer-apps-for-software-platforms</id>
   <title>Killer apps for software platforms</title>
   <published>2013-03-10T00:00:00+00:00</published>
   <updated>2013-03-10T00:00:00+00:00</updated>
   
     <category term="Business"/>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/03/10/killer-apps-for-software-platforms/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;A &lt;em&gt;killer app&lt;/em&gt; is any product that is so desirable that it fuels the sale/adoption of a larger technology that the product depends on.&lt;/p&gt;

&lt;p&gt;The gaming industry has been aware of the power of killer apps for a while, and often seeks to create launch titles for their new gaming systems that are killer apps. Microsoft, for example, deliberately created the first Halo game at same time as their Xbox console. And Nintendo has repeatedly introduced new Mario titles with its new consoles.&lt;/p&gt;

&lt;!-- Similarly, some of the classic examples of killer apps were the first entrants in new software categories: word processors (WordStar) and spreadsheets (VisiCalc and Lotus 1-2-3). --&gt;


&lt;p&gt;However what may not be so obvious is that killer apps exist for learning new software platforms as well, such as for APIs, SDKs, and programming languages.&lt;/p&gt;

&lt;p&gt;Learning a new platform (along with the associated tools and ecosystem) takes a large investment of &lt;em&gt;time&lt;/em&gt;, and so there is a similar barrier to adoption as, say, the monetary cost of buying a new game console.&lt;/p&gt;

&lt;p&gt;I think the platform-builders in the software industry could learn from the gaming industry and strategically introduce killer apps alongside new platform offerings.  I can think of no prior case where this was done deliberately (see the Appendix below), so I think our industry (i.e. software) is really missing out.&lt;/p&gt;

&lt;h3&gt;Appendix&lt;/h3&gt;

&lt;h4&gt;Examples for Programming Languages&lt;/h4&gt;

&lt;p&gt;Killer apps for languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby on Rails -&gt; &lt;strong&gt;Ruby&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Django -&gt; &lt;strong&gt;Python&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Emacs -&gt; &lt;strong&gt;Lisp&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Killer ecosystems for languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iPhone -&gt; &lt;strong&gt;Objective-C&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Android -&gt; &lt;strong&gt;Java&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;embedded scripting in games&lt;/em&gt; -&gt; &lt;strong&gt;Lua&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Killer features for languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;interface with OS natively&lt;/em&gt; -&gt; &lt;strong&gt;C&lt;/strong&gt;, &lt;strong&gt;Objective-C&lt;/strong&gt; (OS X)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;garbage collection&lt;/em&gt; -&gt; &lt;strong&gt;Java&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;hack together a deployable dynamic website fast&lt;/em&gt; -&gt; &lt;strong&gt;PHP&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;general-purpose scripting&lt;/em&gt; -&gt; &lt;strong&gt;Python&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;interprocess scripting on OS X&lt;/em&gt; -&gt; &lt;strong&gt;AppleScript&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Other Software Examples&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;GitHub -&gt; &lt;strong&gt;Git&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Outlook -&gt; &lt;strong&gt;Windows&lt;/strong&gt;&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/08/programming-is-fun-but-what-matters-is-solving-a-real-problem/&quot;&gt;Programming is Fun. But What Matters is Solving a Real Problem.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;More thoughts on business considerations as applied to software.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;More information about the adoption of Lua in the gaming industry on StackOverflow: &lt;a href=&quot;http://stackoverflow.com/questions/38338/why-is-lua-considered-a-game-language&quot;&gt;Why is Lua considered a game language?&lt;/a&gt;&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Although Microsoft has finally created a version of Outlook for the Mac, it is buggy and missing a number of advanced features of the Windows version. Thus two of my colleagues &lt;!-- Neeraj and Dee --&gt; who do a lot of planning run Outlook specifically on Windows despite the workplace being otherwise Mac-oriented.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/03/01/notes-on-racket</id>
   <title>Notes on Racket (PLT-Scheme)</title>
   <published>2013-03-01T00:00:00+00:00</published>
   <updated>2013-03-01T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/03/01/notes-on-racket/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Generally &lt;a href=&quot;http://racket-lang.org&quot;&gt;Racket&lt;/a&gt; appears to be a very usable dialect of Lisp/Scheme.&lt;/p&gt;

&lt;p&gt;Racket is particularly well suited for those who want to develop their own programming language (including those not based on S-expressions), given that the creators of Racket are programming language researchers. For example, a number of Racket subsets have been created to assist students who are learning Racket/Scheme via the &lt;a href=&quot;http://htdp.org&quot;&gt;How to Design Programs&lt;/a&gt; book.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; The Arc language by Paul Graham is also implemented in the Racket environment.&lt;/p&gt;

&lt;p&gt;Racket&amp;rsquo;s developers wanted to make sure it was a &lt;em&gt;practical&lt;/em&gt; language. To that end, there is a bundled IDE (DrRacket) with syntax highlighting, parentheses matching, and integrated debugging. There is also a package management system (PLaneT).&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; And built-in libraries for working with several real-world systems, such as GUIs, networking, databases, JSON/XML, etc. A cross-platform executable can easily be built. And everything is well documented.&lt;/p&gt;

&lt;p&gt;Graphics and GUI programs are supported better than the average language. For example pictures are rendered natively in the Racket REPL, including their use within expressions. And the built-in Racket GUI library is fairly decent.&lt;/p&gt;

&lt;p&gt;The combination of a decent built-in GUI library along with the ability to compile cross-platform executables makes Racket useful for writing cross-platform GUI applications.&lt;/p&gt;

&lt;h2&gt;Racket&amp;rsquo;s GUI library (RacketGUI)&lt;/h2&gt;

&lt;p&gt;The original version of Racket&amp;rsquo;s GUI library was implemented on top of wxWidgets.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; Thus some of wxWidget&amp;rsquo;s poor design decisions leak through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A visual component is called a &amp;ldquo;window&amp;rdquo;, not a control.&lt;/li&gt;
&lt;li&gt;Visual components must be associated with their parent container at creation time.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;However, some fixes were made too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no notion of a wxWidgets &amp;ldquo;sizer&amp;rdquo; as distinct from a &amp;ldquo;container window&amp;rdquo;.

&lt;ul&gt;
&lt;li&gt;This simplifies the mental model considerably, since it is no longer necessary to keep track of both a &amp;ldquo;window&amp;rdquo; hierarchy and a sizer hierarchy.&lt;/li&gt;
&lt;li&gt;Instead, a wxWidgets &amp;ldquo;sizer&amp;rdquo; is represented as a lightweight RacketGUI &amp;ldquo;pane&amp;rdquo;, which can be nested naturally inside containers along with other components.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The event handling loop is managed in the background automatically.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Sadly, RacketGUI lacks some advanced controls I often want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;trees&lt;/li&gt;
&lt;li&gt;tables containing controls in cells

&lt;ul&gt;
&lt;li&gt;However the &lt;code&gt;list-box%&lt;/code&gt; control supports cells that only contain text.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tree-tables&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is not surprising since these controls are hard to implement and are not well-supported by the original underlying wxWidgets library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The wxWidgets tree interface (wxTreeCtrl) is annoying for dynamically generated trees.&lt;/li&gt;
&lt;li&gt;Tables (wxListCtrl) only support text and image cells, not controls as cells.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes several other programming languages and their unique features.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/25/notes-on-prolog/&quot;&gt;Notes on Prolog&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes Prolog, a highly declarative language. Useful for verification of proofs.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;http://htdp.org&quot;&gt;HtDP&lt;/a&gt; book uses the dialects &amp;ldquo;Beginning Student&amp;rdquo;, &amp;ldquo;Intermediate Student&amp;rdquo;, and &amp;ldquo;Advanced Student&amp;rdquo;. These sublanguages restrict the use of certain language features (such as using functions as objects) and can provide better error messages (which avoid mentioning advanced features not supported by the sublanguage).&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;It is possible to import modules directly from the PLaneT repository, which will automatically download and install the module if it isn&amp;rsquo;t already present. Neat!&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Racket&amp;rsquo;s GUI layer has apparently been redone a couple of times. Originally it was based on wxWidgets. Later it was rewritten to about 200,000 lines of C++ glue to Xt, Win32, and Carbon. Then in Racket 5.1 it was replaced with about 80,000 lines of Racket glue to Gtk, Win32, Cocoa, Cairo, and Pango. That&amp;rsquo;s a 60% reduction in code! More details on the &lt;a href=&quot;http://blog.racket-lang.org/2010/12/racket-version-5.html&quot;&gt;Racket blog&lt;/a&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/02/25/notes-on-prolog</id>
   <title>Notes on Prolog</title>
   <published>2013-02-25T00:00:00+00:00</published>
   <updated>2013-02-25T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/02/25/notes-on-prolog/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;h2&gt;What is Prolog?&lt;/h2&gt;

&lt;p&gt;Prolog is a declarative programming language that, given a list of axioms and a list of implication rules, can deduce the truth (or falsehood) of a logical statement.&lt;/p&gt;

&lt;p&gt;For example, given the following knowledge base (AKA &lt;em&gt;database&lt;/em&gt;):&lt;/p&gt;

&lt;pre&gt;
% Axiom: Mary likes Ted.
likes(mary,ted).
% Axiom: Jane likes Ted.
likes(jane,ted).
% Rule: X is jealous of Y if they both like Z (and are not the same person).
jealous(X,Y) :- likes(X,Z), likes(Y,Z), X \= Y.
&lt;/pre&gt;


&lt;p&gt;I can ask the question &lt;code&gt;jealous(mary,jane)&lt;/code&gt; and get the affirmation &lt;code&gt;true&lt;/code&gt;.
Or I can ask the question &lt;code&gt;jealous(mary,mary)&lt;/code&gt; and get the denial &lt;code&gt;false&lt;/code&gt;.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I can also ask a more complicated question containing variables and Prolog will derive the possible values (and relations) the variables must have in order to make the question posed to be true.&lt;/p&gt;

&lt;p&gt;For example, asking the question &lt;code&gt;jealous(X,Y)&lt;/code&gt; will give the results:&lt;/p&gt;

&lt;pre&gt;
X = mary,
Y = jane ;
X = jane,
Y = mary
&lt;/pre&gt;


&lt;p&gt;As another (more interesting) example, consider the knowledge base:&lt;/p&gt;

&lt;pre&gt;
% Rule: A line is horizontal if its points have the same Y coordinate.
horizontal(line( point(_,Y), point(_,Y) )).
% Rule: A line is vertical if its points have the same X coordinate.
vertical(line( point(X,_), point(X,_) )).
&lt;/pre&gt;


&lt;p&gt;And the questions:&lt;/p&gt;

&lt;pre&gt;
(1) horizontal(line( point(0,0), point(X,Y) )).  ==&gt;  Y = 0.
(2) horizontal(line( point(0,0), P2 )).          ==&gt;  P2 = point(_G327, 0).
&lt;/pre&gt;


&lt;p&gt;The second question is particularly interesting because it gave back a fairly complicated answer: &lt;code&gt;P2&lt;/code&gt; must be a &lt;code&gt;point&lt;/code&gt;, its X coordinate can be anything, but its Y coordinate must be zero. I think it&amp;rsquo;s particularly cool that Prolog can deduce that P2 must be a point. &lt;!-- LPN §2.1 --&gt;&lt;/p&gt;

&lt;p&gt;As a final example of a simple problem solvable by Prolog, consider the &lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse7&quot;&gt;crossword puzzle&lt;/a&gt; in Exercise 2.4 of &amp;ldquo;Learn Prolog Now!&amp;rdquo;. You can write a Prolog program to solve crossword puzzles!&lt;/p&gt;

&lt;h2&gt;When is Prolog useful?&lt;/h2&gt;

&lt;p&gt;Prolog&amp;rsquo;s deduction capabilities makes it useful for answering questions and making deductions within systems whose concepts can be expressed in a formal hierarchy. &lt;!-- LPN §2.1 --&gt;&lt;/p&gt;

&lt;p&gt;In academia, for example, Prolog has been used to investigate natural language formalizations and expert systems in artificial intelligence. &lt;!-- LPN §2.1 --&gt;&lt;/p&gt;

&lt;h3&gt;Case Study: Java bytecode verifier&lt;/h3&gt;

&lt;p&gt;As a more practical example, Prolog has also been used to define the semantics of the Java bytecode verifier&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; for Java 6.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; Prior versions of Java had a verifier whose semantics were defined by a textual specification only (namely the Java Virtual Machine Specification).&lt;/p&gt;

&lt;p&gt;There are a few advantages to having the verifier defined in terms of Prolog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The specification becomes formal (and thereby unambiguous and more likely to be error-free).&lt;/li&gt;
&lt;li&gt;The execution model for performing the verification becomes well-defined (since it would use Prolog&amp;rsquo;s) and fast (since Prolog&amp;rsquo;s core unification algorithm is fast&lt;!-- LPN §2.1 --&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Writing Programs&lt;/h2&gt;

&lt;h3&gt;Functions as Rules&lt;/h3&gt;

&lt;p&gt;So how do you actually write something resembling a &lt;em&gt;program&lt;/em&gt; in Prolog? Until now we&amp;rsquo;ve been talking about axioms, rules, and questions. But in most languages a program consists of a series of expressions that are evaluated.&lt;/p&gt;

&lt;p&gt;For example in Python, you might write:&lt;/p&gt;

&lt;pre&gt;
def add(x, y):
    return x + y

print add(5, 3)    # prints 8
&lt;/pre&gt;


&lt;p&gt;In Prolog, you can do something similar by defining a rule where one of the variables in the rule (typically the last one) is its &amp;ldquo;output&amp;rdquo;:&lt;/p&gt;

&lt;pre&gt;
add(X, Y, Result) :- Result is X + Y.
&lt;/pre&gt;


&lt;p&gt;To actually evaluate this &amp;ldquo;function&amp;rdquo; with 5 and 3 you would ask the question &lt;code&gt;add(5, 3, Result)&lt;/code&gt; which would yield &lt;code&gt;Result = 8&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, don&amp;rsquo;t get trapped into the idea that such as rule always needs to be evaluated in one direction. In Prolog you have the additional power to ask what the &amp;ldquo;inputs&amp;rdquo; of the function has to be to yield an already-known &amp;ldquo;output&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;For example, you could ask the question &lt;code&gt;add(X, 3, 8)&lt;/code&gt; to deduce that &amp;ldquo;input&amp;rdquo; X must be 5.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; You could even try asking &lt;code&gt;add(X, Y, 8)&lt;/code&gt; to find all values of X and Y that yield 8 as a result (although there are an infinite number of such combinations in this example).&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This power to flip functions on their head is a unique quality of Prolog. (And it blows my mind.)&lt;/p&gt;

&lt;p&gt;Ultimately a rule specifies a set of relationships between its arguments. Thus arguments can be &amp;ldquo;inputs&amp;rdquo;, &amp;ldquo;outputs&amp;rdquo;, or even temporary variables (like accumulators).&lt;/p&gt;

&lt;h3&gt;Processing Recursive Data Structures&lt;/h3&gt;

&lt;p&gt;Processing recursive data structures such as lists and trees is mind bending&amp;hellip; For examples see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse24&quot;&gt;LPN §6.1 &amp;ldquo;Append&amp;rdquo;&lt;/a&gt; and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse25&quot;&gt;LPN §6.2 &amp;ldquo;Reversing a List&amp;rdquo;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Interactive Use (as a REPL)&lt;/h2&gt;

&lt;p&gt;It is possible to run Prolog in an interactive fashion by using the &lt;code&gt;assert&lt;/code&gt; special rule at runtime to define new statements (i.e. axioms and rules). And &lt;code&gt;listing&lt;/code&gt; will display the set of statements that have been defined. Finally &lt;code&gt;retract&lt;/code&gt; and &lt;code&gt;retractall&lt;/code&gt; can be used to undefine statements.&lt;/p&gt;

&lt;p&gt;These special rules, however, are not restricted to use in the interpreter - they can also be used at runtime by rules in programs. For example memoization&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; is a good use for dynamic calls to &lt;code&gt;assert&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Question Evaluation &lt;small&gt;(Unification, Backtracking)&lt;/small&gt;&lt;/h2&gt;

&lt;p&gt;When evaluating a question, Prolog takes the question expression and matches it against the axioms and rules in the input knowledge base. The algorithm used for matching is called &lt;em&gt;unification&lt;/em&gt;. While performing unification, Prolog makes guesses about what values should be assigned to each variable in the question expression. If it encounters a contradiction, it &lt;em&gt;backtracks&lt;/em&gt; to one of its previous guesses and revises the guess. This process is described graphically in &lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse6&quot;&gt;LPN §2.2 &amp;ldquo;Proof Search&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although Prolog is a declarative language, the precise behavior of evaluating queries depends on the order that rules and clauses are defined. In particular the performance of the same program can vary significantly depending on ordering. As another gotcha, if you define rules in a left-recursive fashion (as opposed to a right-recursive one), Prolog will go into an infinite loop when evaluating the rule.&lt;/p&gt;

&lt;p&gt;It is possible to debug (and step through) the evaluation of a question expression using the &lt;strong&gt;trace&lt;/strong&gt; command, which is described in &lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse8&quot;&gt;LPN §2.4 &amp;ldquo;Practical Session&amp;rdquo;&lt;/a&gt;. This is useful for investigating performance issues.&lt;/p&gt;

&lt;h3&gt;Cuts&lt;/h3&gt;

&lt;p&gt;It is possible to optimize the execution of a Prolog rule by adding a &lt;strong&gt;cut&lt;/strong&gt; as a clause. This is written as a bang (&lt;code&gt;!&lt;/code&gt;). Unfortunately to use cuts effectively (and correctly), you have to understand the exact execution model used by Prolog. It is quite easy to unwittingly insert a cut that actually changes the semantics of the original rule. &lt;!-- LPN §10.1, §10.2 --&gt;&lt;/p&gt;

&lt;p&gt;There are even hacks you can do with cuts such as implementing &amp;ldquo;negation as failure&amp;rdquo; (&lt;code&gt;\+&lt;/code&gt;). But again you have to be very careful since cuts can change your knowledge base&amp;rsquo;s semantics. &lt;!-- LPN §10.3 --&gt;&lt;/p&gt;

&lt;h2&gt;Side Effects &amp;amp; I/O&lt;/h2&gt;

&lt;p&gt;Some built-in clauses trigger side effects when they are examined by the unification algorithm. Programs take advantage of such &amp;ldquo;impure predicates&amp;rdquo; to do I/O and other types of side-effecting work.&lt;/p&gt;

&lt;p&gt;For example asking the question &lt;code&gt;print('Hello')&lt;/code&gt; will print &lt;code&gt;Hello&lt;/code&gt; to the screen.&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;To write to a file you might define:&lt;/p&gt;

&lt;pre&gt;
printfile(Filename, Text) :-
    open(Filename, write, Stream),
    write(Stream, Text), nl(Stream),
    close(Stream).
&lt;/pre&gt;


&lt;p&gt;And then pose the question &lt;code&gt;printfile('hogwarts.txt', 'Hogwarts')&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;During evaluation, the &lt;code&gt;printfile&lt;/code&gt; is rewritten to &lt;code&gt;open(...) AND write(...) AND nl(...) AND close(...)&lt;/code&gt;. Each of those subclauses is then each evaluated to &lt;code&gt;true&lt;/code&gt; (performing the associated side effect) and the overall clause becomes just &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;References&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;LPN: &lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pageid=online&quot;&gt;Learn Prolog Now!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes several other programming languages and their unique features.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;When posing a question in the Prolog interpreter, you must include a trailing period at the end of the question.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;The job of the Java bytecode verifier is to examine a compiled Java program and check whether it is well-structured and therefore (reasonably) safe for the Java virtual machine to execute. For example the verifier would reject a Java program containing a command to jump to an instruction location outside of the current method.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;See the &lt;a href=&quot;http://docs.oracle.com/javase/specs/jvms/se7/html/index.html&quot;&gt;Java Virtual Machine Specification&lt;/a&gt;. Particularly &amp;ldquo;Preface to the Java SE 7 Edition&amp;rdquo; and §4.10 &amp;ldquo;Verification of class Files&amp;rdquo;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;Unfortunately the &lt;code&gt;is&lt;/code&gt; clause in this example cannot be run &amp;ldquo;backwards&amp;rdquo;, so this particular question will fail. (I am not sure why this particular restriction on &lt;code&gt;is&lt;/code&gt; exists.)&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;A Prolog &lt;em&gt;program&lt;/em&gt; that wanted to collect all combinations of inputs in this fashion (as opposed to a user at the interpreter) would probably use a combination of the &lt;code&gt;findall&lt;/code&gt;, &lt;code&gt;bagof&lt;/code&gt;, and &lt;code&gt;setof&lt;/code&gt; special rules. See &lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse49&quot;&gt;LPN §11.2 &amp;ldquo;Collecting Solutions&amp;rdquo;&lt;/a&gt; for more information.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;Memoization is where a function that computes a value caches the result of the computation so that repeated invocations with the same input can immediately return the saved result. This can speed of performance in certain applications. See &lt;a href=&quot;http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;amp;pageid=lpn-htmlse48&quot;&gt;LPM §11.1 &amp;ldquo;Database Manipulation&amp;rdquo;&lt;/a&gt; for an example.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;Note that &lt;code&gt;'Hello'&lt;/code&gt; (with single quotes) is a variable, not a string. The string &lt;code&gt;&quot;Hello&quot;&lt;/code&gt; (with double quotes) is equivalent to a list of codepoints (&lt;code&gt;[72, 101, 108, 108, 111]&lt;/code&gt;).&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/02/20/visual-guide-to-programming-language-properties</id>
   <title>Visual Guide to Programming Language Properties</title>
   <published>2013-02-20T00:00:00+00:00</published>
   <updated>2013-02-20T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/02/20/visual-guide-to-programming-language-properties/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;Here&amp;rsquo;s an interactive chart showing high-level properties of various programming languages.&lt;br/&gt;
You can filter the chart to only show the properties that your favorite language supports.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2013/02/20/visual-guide-to-programming-language-properties/&quot;&gt;Read more&amp;hellip;&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/02/02/rdiscount-2.0.7-released</id>
   <title>RDiscount 2.0.7 released</title>
   <published>2013-02-02T00:00:00+00:00</published>
   <updated>2013-02-02T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/02/02/rdiscount-2.0.7-released/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;It has been just over two years since &lt;a href=&quot;/projects/rdiscount/&quot;&gt;RDiscount&lt;/a&gt; 1.6.8 (the previous version) was posted.&lt;br/&gt;
As the new maintainer, I intend to provide updates a bit more frequently. :-)&lt;/p&gt;

&lt;p&gt;Update to the latest version with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem update rdiscount
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;What&amp;rsquo;s New?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://michelf.ca/projects/php-markdown/extra/#footnotes&quot;&gt;Footnotes&lt;/a&gt; - from &lt;em&gt;PHP Markdown Extra&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Superscript tweaks

&lt;ul&gt;
&lt;li&gt;Be more picky about what comes before a ^ if we’re superscripting.&lt;/li&gt;
&lt;li&gt;Modify superscript grabbing so that it grabs parenthetical and alphanumeric blocks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Other bug fixes

&lt;ul&gt;
&lt;li&gt;Table-of-contents generation will no longer crash for header items containing links.&lt;/li&gt;
&lt;li&gt;Adjacent new-style [link]s are no longer incorrectly combined.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;What&amp;rsquo;s Next?&lt;/h2&gt;

&lt;p&gt;RDiscount 2.1.5 will be the next release of RDiscount. Planned features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fenced code blocks

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.github.com/github-flavored-markdown/&quot;&gt;backtick-delimited&lt;/a&gt; - from &lt;em&gt;GitHub Flavored Markdown&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://michelf.ca/projects/php-markdown/extra/#fenced-code-blocks&quot;&gt;tilde-delimited&lt;/a&gt; - from &lt;em&gt;PHP Markdown Extra&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Who am I?&lt;/h2&gt;

&lt;p&gt;I should also introduce myself: I am &lt;a href=&quot;/about/&quot;&gt;David Foster&lt;/a&gt;, the new maintainer for RDiscount.&lt;/p&gt;

&lt;p&gt;Since I am using RDiscount on my personal website, you can expect continued updates as major new features are introduced in the underlying &lt;a href=&quot;http://www.pell.portland.or.us/~orc/Code/discount/&quot;&gt;Discount&lt;/a&gt; library.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2012/12/16/why-i-no-longer-use-drupal/&quot;&gt;Why I no longer use Drupal&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Why Jekyll (and not Drupal) is awesome for making a personal website or blog.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Jekyll can use RDiscount for Markdown rendering.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/02/01/learnings-from-sicp</id>
   <title>Learnings from SICP (and Lisp)</title>
   <published>2013-02-01T00:00:00+00:00</published>
   <updated>2013-02-01T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/02/01/learnings-from-sicp/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/2013/sicp_cover.jpg&quot;
  alt=&quot;Cover of The Structure and Interpretation of Computer Programs&quot;
  style=&quot;float: right;&quot;
  width=&quot;170&quot; height=&quot;246&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Recently I took the liberty of reading one of the defining books in the domain of computer science: &lt;a href=&quot;http://mitpress.mit.edu/sicp/&quot;&gt;The Structure and Interpretation of Computer Programs&lt;/a&gt;, often abbreviated as SICP.&lt;/p&gt;

&lt;p&gt;SICP is the computer science textbook given to undergraduates at MIT. It serves as an advanced text on software design and as an introductory text for the Lisp programming language.&lt;/p&gt;

&lt;p&gt;Here are some interesting things I learned:&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;#role-of-programming-languages&quot;&gt;Role of Programming Languages&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#abstract-data-types&quot;&gt;Abstract Data Types&lt;/a&gt;&lt;/li&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#lisp-vs-pascal-design-philosophies&quot;&gt;Lisp vs. Pascal Design Philosophies&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#polymorphism&quot;&gt;Polymorphism&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#cross-type-operations&quot;&gt;Cross-Type Operations&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li&gt;&lt;a href=&quot;#assignments-mutable-state-and-side-effects&quot;&gt;Assignments, Mutable State, and Side Effects&lt;/a&gt;&lt;/li&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#lazy-evaluation&quot;&gt;Lazy Evaluation&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li&gt;&lt;a href=&quot;#declarative-languages&quot;&gt;Declarative Languages&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;role-of-programming-languages&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Role of Programming Languages&lt;/h2&gt;

&lt;p&gt;Languages should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provide the means for &lt;strong&gt;combining simple ideas to form complex ideas&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;provide the means for &lt;strong&gt;abstracting units of computation&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;serve as a framework within which we &lt;strong&gt;organize our ideas about processes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Units of computation can be abstracted in several forms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;procedure&lt;/strong&gt; - &lt;em&gt;Assigns names to common patterns, allowing you to work in terms of the named abstractions directly.&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;AKA function, method&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;abstract data type&lt;/strong&gt; - &lt;em&gt;Allows the choice of representation (i.e. the implementation) to vary separately from the API (i.e. the interface).&lt;/em&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;

&lt;ul&gt;
&lt;li&gt;Built-in language support is often provided in the form of &lt;strong&gt;classes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;See also: LISP constructors

&lt;ul&gt;
&lt;li&gt;AKA &lt;strong&gt;constructor&lt;/strong&gt; or &lt;strong&gt;static factory method&lt;/strong&gt; in other languages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;See also: LISP selectors

&lt;ul&gt;
&lt;li&gt;AKA &lt;strong&gt;accessors&lt;/strong&gt;, mutators, or &lt;strong&gt;properties&lt;/strong&gt; in other languages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;module&lt;/strong&gt;&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; - &lt;em&gt;Groups several procedures and data types into a namespace independent from other modules.&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;AKA package (Java), namespace (C++), module (Python)&lt;/li&gt;
&lt;li&gt;Languages that don&amp;rsquo;t have built-in support for this concept typically use prefixes to create de-facto namespaces. (C, Objective-C, PHP &amp;lt; 5.3.0)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;assembly&lt;/strong&gt; - &lt;em&gt;Groups several modules together in a single versioned &lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; package. Assemblies can depend on other assemblies, often from separate vendors.&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;AKA &lt;strong&gt;shared library&lt;/strong&gt; (C, C++), gem (Ruby), egg (Python)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;abstract-data-types&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Abstract Data Types&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;lisp-vs-pascal-design-philosophies&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Lisp vs. Pascal Design Philosophies&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;For you youngin&amp;rsquo;s that have never used Pascal, just replace &amp;ldquo;Pascal&amp;rdquo; with &amp;ldquo;Java&amp;rdquo; in this section and you should get the right idea.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two design philosophies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lisp-school&lt;/strong&gt;: Create abstract data types by combining a &lt;em&gt;small&lt;/em&gt; set of general-purpose data types (particularly collections). These complex structures can then be manipulated using operations on these general-purpose types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&amp;ldquo;Lisp is for building organisms -­ imposing, breathtaking, dynamic structures built by squads fitting fluctuating myriads of simpler organisms into place.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&amp;ldquo;Lisp programs inflate libraries with functions whose utility transcends the application that produced them.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pascal-school&lt;/strong&gt;: Create &lt;em&gt;many&lt;/em&gt; special-purpose data types (i.e. classes) and specialized operations to manipulate them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&amp;ldquo;Pascal is for building pyramids -­ imposing, breathtaking, static structures built by armies pushing heavy blocks into place.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&amp;ldquo;In Pascal the plethora of declarable data structures induces a specialization within functions that inhibits and penalizes casual cooperation.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Roughly speaking, I think of the Lisp philosophy as &lt;strong&gt;programming with collections&lt;/strong&gt; and the Pascal philosophy as &lt;strong&gt;programming with classes&lt;/strong&gt;.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h4&gt;Usage&lt;/h4&gt;

&lt;p&gt;The Pascal philosophy has won out in most statically typed languages such as C++ and Java, and in languages with poor (or nonexistent) built-in collections.&lt;/p&gt;

&lt;p&gt;The Lisp philosophy is more common in dynamically typed languages that lack built-in support for classes, such as Lisp itself and JavaScript.&lt;/p&gt;

&lt;p&gt;A hybrid approach (using both philosophies) is seen in languages that are dynamically typed, have built-in collections, and have built-in classes, such as Python and Ruby.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;polymorphism&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Polymorphism&lt;/h3&gt;

&lt;p&gt;Polymorphism is where multiple abstract data types implement a common &lt;em&gt;interface&lt;/em&gt;, which is typically defined as a series of methods that can be called on all implementing types.&lt;/p&gt;

&lt;p&gt;This allows client code, when given an object known only to implement a particular interface, to invoke interface methods on the object and end up calling the correct implementation of that method depending on the runtime type of the object.&lt;/p&gt;

&lt;h4&gt;Implementation Strategies&lt;/h4&gt;

&lt;p&gt;Polymorphism can be implemented in several different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Switch on Typecode&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Easiest to implement. Hardest to maintain.&lt;/li&gt;
&lt;li&gt;Treated as an anti-pattern in many OO languages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual Lookup Tables&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;AKA &amp;ldquo;data-directed programming&amp;rdquo; (in SICP) or v-tables (C++)&lt;/li&gt;
&lt;li&gt;Default implementation strategy for most OO languages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Passing&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Most flexible.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Many languages provide a &lt;em&gt;default implementation strategy&lt;/em&gt; as a language construct. For example C++ and Java use virtual lookup tables. Smalltalk and Objective-C use message passing. C doesn&amp;rsquo;t give you anything for free, so you have to roll your own polymorphism.&lt;/p&gt;

&lt;h4&gt;Tradeoffs&lt;/h4&gt;

&lt;p&gt;These implementation strategies for polymorphism have some tradeoffs, which are worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Virtual lookup tables are restricted in that &lt;em&gt;the total set of operations on the abstract data type must be known in advance&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Message passing, on the other hand, can be made more flexible:

&lt;ul&gt;
&lt;li&gt;Implementing data types may choose to support more operations than the standard set on the interface.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Heck, individual &lt;em&gt;instances&lt;/em&gt; can choose to support more operations than the standard set.

&lt;ul&gt;
&lt;li&gt;In such cases, you would want to interrogate (i.e. reflect on) an individual instance to determine what operations (i.e. messages) it understands/supports.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;cross-type-operations&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Cross-Type Operations&lt;/h3&gt;

&lt;p&gt;Introducing &lt;strong&gt;cross-type operations&lt;/strong&gt;, such as &lt;code&gt;add(Integer, Complex)&lt;/code&gt;, is a very tricky design issue.&lt;/p&gt;

&lt;p&gt;Having explicit functions that operate on all combinations of types is possible but highly verbose. With &lt;strong&gt;n&lt;/strong&gt; types and &lt;strong&gt;m&lt;/strong&gt; operations, you need &lt;strong&gt;n*m&lt;/strong&gt; functions to implement all combinations. Impractical.&lt;/p&gt;

&lt;p&gt;Another strategy is to use &lt;em&gt;coercion&lt;/em&gt; to convert a value from one type to another. So instead of defining &lt;code&gt;add(Integer, Complex)&lt;/code&gt;, just define &lt;code&gt;convertToComplex(Integer) : Complex&lt;/code&gt;, and use the existing &lt;code&gt;add(Complex, Complex)&lt;/code&gt;. To convert between all types requires at least &lt;strong&gt;n&lt;/strong&gt; but no more than &lt;strong&gt;n&lt;sup&gt;2&lt;/sup&gt;&lt;/strong&gt; conversion functions.&lt;/p&gt;

&lt;p&gt;Many programming languages have built-in facilities to automatically coerce types. For some languages (like JavaScript or PHP) these coersion rules are quite complex (and error-prone). Other languages (like ML) ban implicit coercion entirely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java only has coercion for built-in types.&lt;/li&gt;
&lt;li&gt;C++ lets the datatype designer choose (via &lt;code&gt;implicit&lt;/code&gt; or explicit one-argument constructors).&lt;/li&gt;
&lt;li&gt;Scala relies on implicit coercion a lot to enable foreign methods to be introduced on types.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;One wrinkle is that these conversion functions might introduce a loss in precision. For example not every integer can be represented as double of exactly the same value.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;assignments-mutable-state-and-side-effects&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Assignments, Mutable State, and Side Effects&lt;/h2&gt;

&lt;p&gt;Introducing assignment creates lots of complications. In particular &lt;em&gt;referential transparency&lt;/em&gt; is lost. Optimizations related to reordering and coalescing expressions need to be a lot more careful. Static reasoning of various kinds is impaired.&lt;/p&gt;

&lt;p&gt;To reduce bugs it is best to minimize the use of mutation by using immutable objects whenever possible.&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Haskell takes a very aggressive stance against assignments, mutable state, and other side effects: they are banned by default. However Haskell does allow side effects within the context of a &lt;strong&gt;monad&lt;/strong&gt;. This is a special construct unique to Haskell (so far as I know).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;lazy-evaluation&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Lazy Evaluation&lt;/h3&gt;

&lt;p&gt;Normally expressions are evaluated immediately, in the order that they occur in code. &lt;strong&gt;Lazy evaluation&lt;/strong&gt; changes this behavior such that expressions are only evaluated when some primitive operation (like print or add) requires the value of the expression. Until then the unevaluated expression is passed around (as a &amp;ldquo;thunk&amp;rdquo;).&lt;/p&gt;

&lt;p&gt;Lazy evaluation enables that creation of &lt;strong&gt;lazy data structures&lt;/strong&gt;, which is a useful performance optimization in some contexts.&lt;/p&gt;

&lt;p&gt;Unrestricted mutation and lazy evaluation do not mix well in programming languages. Since unrestricted mutation is very common in mainstream programming languages, it is quite rare to be in an environment that supports lazy evaluation. Haskell is one of the few.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;declarative-languages&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Declarative Languages&lt;/h2&gt;

&lt;p&gt;Logic programming languages are at the far declarative end of the
imperative-declarative spectrum. They can be used to deduce answers
from a set of initial set of declarative statements.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2013/02/25/notes-on-prolog/&quot;&gt;Prolog&lt;/a&gt; is the best-known example of a logic programming language.&lt;/p&gt;

&lt;p&gt;Query systems for databases are a type of logic programming language.&lt;/p&gt;

&lt;p&gt;A &amp;ldquo;query&amp;rdquo; (i.e. an expression in the language) is transformed into a
&amp;ldquo;query plan&amp;rdquo; (i.e. a specific set of steps to follow) by a query planner. The implementation of these planners is quite complex.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;conclusion&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So those are a few interesting things I learned from reading SICP. Taking notes while reading made it a lot easier for me to remember the content. You might try it when reading a technical book with a lot of new concepts.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/03/01/notes-on-racket/&quot;&gt;Notes on Racket&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes Racket, a dialect of Lisp with batteries included.&lt;/em&gt;&lt;br/&gt;
&lt;em&gt;Useful for implementing other languages and creating cross-platform GUI programs.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/29/unique-features-of-various-programming-languages/&quot;&gt;Unique Features of Various Programming Languages&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Discusses several programming languages and their unique features.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/25/notes-on-prolog/&quot;&gt;Notes on Prolog&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes the Prolog language in more detail.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;For example, complex numbers can be expressed in rectangular (a + b&lt;em&gt;i&lt;/em&gt;) or polar form (r*cos(𝜽)). &amp;ndash; Some representations are better than others for different operations. Adding works better in rectangular form. Multiplying works better in polar form.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;SICP does not mention the notion of a &lt;em&gt;module&lt;/em&gt; or an &lt;em&gt;assembly&lt;/em&gt;, however these are common higher-level units for abstracting computation in languages other than Lisp.&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Versioning assemblies effectively is a challenging topic onto itself. If done without care you get so-called &amp;ldquo;dependency hell&amp;rdquo;. Just getting a consistent version numbering scheme can be tricky. One popular versioning scheme is codified as &lt;a href=&quot;http://semver.org&quot;&gt;Semantic Versioning&lt;/a&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;In my opinion, a language that supports neither first-class collections nor first-class classes is non-viable for large scale general purpose software development. C, Assembly, and Fortran fall into this category.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;For example, the Linux virtual filesystem, which is implemented in message-passing style, has a common set of operations that all filesystems are expected to support (ex: &lt;code&gt;unlink&lt;/code&gt;). However individual filesystems may support additional operations: For example the HFS+ filesystem on Mac OS X additionally supports a &lt;code&gt;delete&lt;/code&gt; operation, which has slightly different semantics than the standard &lt;code&gt;unlink&lt;/code&gt; operation.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;A common case where eliminating mutation may &lt;em&gt;not&lt;/em&gt; be practical is when defining and working with large data structures that need many small updates made to them over time. If such a structure were made immutable, there would be a large performance penalty for recopying the entire structure whenever a small change needed to be made.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/01/29/unique-features-of-various-programming-languages</id>
   <title>Unique Features of Various Programming Languages</title>
   <published>2013-01-29T00:00:00+00:00</published>
   <updated>2013-02-18T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/01/29/unique-features-of-various-programming-languages/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;blockquote&gt;
  A language that doesn't affect the way you think about programming, is not worth knowing.&lt;br/&gt;
  &lt;br/&gt;
  &amp;ndash; &lt;a href=&quot;http://www-pu.informatik.uni-tuebingen.de/users/klaeren/epigrams.html&quot;&gt;Alan Perlis&lt;/a&gt;
&lt;/blockquote&gt;


&lt;p&gt;I like learning new languages to get myself to think about problems in different ways.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a list of a few well-known languages I&amp;rsquo;ve worked with and some of the more interesting features I&amp;rsquo;ve encountered:&lt;/p&gt;

&lt;div class=&quot;toc&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#c&quot;&gt;C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#java&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csharp&quot;&gt;C&amp;#35;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#python&quot;&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#javascript&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#haskell&quot;&gt;Haskell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#lisp&quot;&gt;Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#other&quot;&gt;Other&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;p&gt;&lt;a id=&quot;c&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;C&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Undefined behavior&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The idea that a language specification would explicitly specify certain constructs as having undefined behavior is interesting. Most specifications leave things undefined by omission, not commission.&lt;/li&gt;
&lt;li&gt;Although this allows various compiler optimizations, many developers rely on their particular compiler&amp;rsquo;s implementation of undefined behavior without even realizing it.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;java&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Java&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objects are the primary unit of composition&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;There are no standalone functions.&lt;/li&gt;
&lt;li&gt;Design Patterns can be used to describe high level object coordination patterns.&lt;/li&gt;
&lt;li&gt;However sometimes the community&amp;rsquo;s focus on objects can be a bit extreme.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checked exceptions&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Great when used &lt;em&gt;sparingly&lt;/em&gt;, as it forces the caller to handle expected error conditions.

&lt;ul&gt;
&lt;li&gt;I do think that it was a usability error to make &lt;code&gt;Exception&lt;/code&gt; checked and &lt;code&gt;RuntimeException&lt;/code&gt; unchecked. Rather it should be &lt;code&gt;Exception&lt;/code&gt; that is &lt;em&gt;unchecked&lt;/em&gt; and a new &lt;code&gt;CheckedException&lt;/code&gt; should be the base for all checked exceptions. This makes it clear that &lt;em&gt;unchecked&lt;/em&gt; exceptions should be the default.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Managing checked exceptions &lt;em&gt;correctly&lt;/em&gt; is quite difficult. &lt;!-- TODO: ARTICLE-IDEA --&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unicode strings&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Tons of other languages use &amp;ldquo;bytestrings&amp;rdquo; as the main string type which causes all kinds of problems when working with international characters. &lt;!-- TODO: ARTICLE-IDEA --&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation focus&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Every library is expected to have JavaDoc documentation, which is generated from documentation comments in the source&lt;/li&gt;
&lt;li&gt;This is really powerful, since it makes it easy for developers to write documentation, and to do so at the same time the implementation is coded, when the desired behavior is most fresh in the mind.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility focus&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I have never seen a community so focused on maintaining backward compatibility. I can&amp;rsquo;t think of a single deprecated method in the Java library that was actually deleted.&lt;/li&gt;
&lt;li&gt;Even the Java Language Specification has an entire chapter devoted to &lt;a href=&quot;http://docs.oracle.com/javase/specs/jls/se5.0/html/binaryComp.html&quot;&gt;binary compatibility&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;This focus may be partially attributable to the early mantra of &lt;a href=&quot;http://en.wikipedia.org/wiki/Write_once,_run_anywhere&quot;&gt;Write once, run anywhere&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Garbage Collection&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Being freed from the confines of manual memory management makes it a ton easier to focus on more important things.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;csharp&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;C&amp;#35;&lt;/h3&gt;

&lt;p&gt;Very similar to Java.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Assemblies&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is a level of encapsulation above the typical namespaces or modules in most languages. Assemblies are similar to the idea of static/dynamic libraries in C or JAR files in Java.&lt;/li&gt;
&lt;li&gt;Notably, you can mark members as &lt;code&gt;internal&lt;/code&gt;, which makes them public within the same assembly, but private to everybody outside the assembly. This is quite useful.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-language compatibility is first-class&lt;/strong&gt; (not just for C)

&lt;ul&gt;
&lt;li&gt;C# runs in the Common Language Runtime, which was designed from the beginning to support interoperability between languages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Properties are first-class&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;No longer need to write explicit getter and (optional) setter methods.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listeners are first-class&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Classes can declare an &lt;em&gt;event&lt;/em&gt; &lt;code&gt;Foo&lt;/code&gt; with &lt;code&gt;addFooListener&lt;/code&gt; and &lt;code&gt;removeFooListener&lt;/code&gt; functionality built in.&lt;/li&gt;
&lt;li&gt;Unfortunately the implementation has some annoyances&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foreign Methods&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; are first-class&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;C# calls these &lt;em&gt;extension methods&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partial Classes&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Allows a class&amp;rsquo;s members to be defined in multiple files.&lt;/li&gt;
&lt;li&gt;Useful to add functionality to a generated class (for example, from a parser generator) without those modifications getting lost when the class is next regenerated.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;python&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Python&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Indentation is significant&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Everyone notices this pretty fast.&lt;/li&gt;
&lt;li&gt;Overall I think requiring correct indentation is a Good Thing™, as it contributes directly to &lt;em&gt;readable&lt;/em&gt; code.&lt;/li&gt;
&lt;li&gt;However this makes lambda expressions much less powerful than in other languages, since you can&amp;rsquo;t easily nest statements inside a lambda expression without explicit braces (or similar delimiters).&lt;/li&gt;
&lt;li&gt;Another side effect of having significant indentation is that the choice of tabs vs. spaces really matters. If you mix them, your program probably won&amp;rsquo;t run.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive interpreter (REPL)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Amazingly useful for prototyping quickly, running experiments, and learning the language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collections are first class&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You can type &lt;code&gt;[1,2,3]&lt;/code&gt; to get a list, &lt;code&gt;{'key': 'value'}&lt;/code&gt; to get a dictionary, and &lt;code&gt;{1,2,3}&lt;/code&gt; to get a set. So much faster than &lt;code&gt;new ArrayList&amp;lt;Integer&amp;gt;(...)&lt;/code&gt;, &lt;code&gt;new HashMap&amp;lt;Integer&amp;gt;(...)&lt;/code&gt;, or &lt;code&gt;new HashSet&amp;lt;Integer&amp;gt;(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functions are first class&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You can declare them as literals, pass them around, and create higher-order functions that take functions as parameters.&lt;/li&gt;
&lt;li&gt;Functions can also live on their own without an enclosing class, in contrast to Java. This is often the simplest approach for a given implementation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Magic&amp;rdquo; marked explicitly&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Anything &amp;ldquo;magic&amp;rdquo; that the language treats specially has names surrounded by double underscores.&lt;/li&gt;
&lt;li&gt;For example:

&lt;ul&gt;
&lt;li&gt;An object&amp;rsquo;s constructor is called &lt;code&gt;__init__&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The method implementing an operator overload for plus is called &lt;code&gt;__add__&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A class&amp;rsquo;s metaclass is held by the &lt;code&gt;__metaclass__&lt;/code&gt; field.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generators&lt;/strong&gt; and &lt;strong&gt;Coroutines&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Generators enable straightforward &lt;em&gt;pulling&lt;/em&gt; of values from a complex data source (like a parsed data structure).&lt;/li&gt;
&lt;li&gt;Coroutines enable straightforward &lt;em&gt;pushing&lt;/em&gt; of values to a complex data sink.&lt;/li&gt;
&lt;li&gt;Python calls both constructs a &lt;em&gt;generator&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;javascript&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;JavaScript&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No blocking I/O&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;All I/O is non-blocking and asynchronous. This results in heavy use of &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuation-passing_style&quot;&gt;continuation passing style&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Successful despite huge flaws&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Ease of deployment and ubiquity (i.e. business considerations) trump ease of use. (PHP also wins for the same reason.)&lt;/li&gt;
&lt;li&gt;A few flaws:

&lt;ul&gt;
&lt;li&gt;Everything is in the one global namespace.&lt;/li&gt;
&lt;li&gt;No user-defined namespaces, modules, or importing of other files.&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;No built-in facility for classes.&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Bizarre loose semantics for &lt;code&gt;==&lt;/code&gt;.&lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Multiple illegal value sentinels: &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt;.&lt;sup id=&quot;fnref:9&quot;&gt;&lt;a href=&quot;#fn:9&quot; rel=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON (JavaScript Object Notation)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;A fantastically compact, readable, and portable notation for representing all kinds of data structures. Great for data interchange.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;haskell&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Haskell&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lazy evaluation&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Expressions are only evaluated when some primitive operation (like &lt;code&gt;print&lt;/code&gt; or &lt;code&gt;add&lt;/code&gt;) requires the value of the expression.&lt;/li&gt;
&lt;li&gt;Allows you to glue programs together in new ways. In particular, execution
of multiple functions can be interleaved trivially and termination
conditions can be separated from looped computation.

&lt;ul&gt;
&lt;li&gt;This is explained in more detail in &lt;a href=&quot;http://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf&quot;&gt;Why Functional Programming (1990)&lt;/a&gt;,
§4 &amp;ldquo;Gluing Programs Together&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Allows you to extract complex expressions without fear of introducing a performance hit (since the expression will only actually be evaluated if it is needed).&lt;/li&gt;
&lt;li&gt;Allows you to define your own control flow operators.&lt;sup id=&quot;fnref:10&quot;&gt;&lt;a href=&quot;#fn:10&quot; rel=&quot;footnote&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Side effects banned by default&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Mutation of data structures and I/O, both of which have order-sensitive side effects, are not allowed except within the confines of &lt;strong&gt;monad&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;monad&lt;/strong&gt; is a construct that explicitly controls evaluation order, in contrast to the usual unpredictable lazy evaluation behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;null&lt;/code&gt; banned by default.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Unlike many languages, there is no special &lt;code&gt;null&lt;/code&gt; value in Haskell that can be substituted anywhere.&lt;/li&gt;
&lt;li&gt;Instead if a function wants to return a value of type &lt;code&gt;T&lt;/code&gt; or null, you would declare the function as returning type &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt;, which could either have the value &lt;code&gt;Some(tValue)&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;. When declared in this way, callers are &lt;em&gt;required&lt;/em&gt; to handle both possibilies.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type inference (+ static typing)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The benefits of static typing without the need to specify the types for everything?&lt;br/&gt;
Count me in!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;lisp&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Lisp &lt;small&gt;(Common Lisp, Scheme, Clojure)&lt;sup id=&quot;fnref:11&quot;&gt;&lt;a href=&quot;#fn:11&quot; rel=&quot;footnote&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/small&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Homoiconic&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;When you write a Lisp program, the notation you use (the &lt;em&gt;grammar&lt;/em&gt;) is equivalent to what a compiler would see (an &lt;em&gt;abstract syntax tree&lt;/em&gt; or &lt;em&gt;AST&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Furthermore this Lisp code is represented as a nested structure of lists, symbols, and literals, all of which can be directly generated and manipulated in Lisp itself!&lt;/li&gt;
&lt;li&gt;This allows Lisp code to generate list structures which can then be run as Lisp code directly.

&lt;ul&gt;
&lt;li&gt;Generation can be done at &lt;em&gt;compile&lt;/em&gt; time with &lt;strong&gt;macros&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Generation can be done at &lt;em&gt;runtime&lt;/em&gt; as well, and then invoked with &lt;strong&gt;eval&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;However the highly uniform structure of Lisp code, devoid of operator and syntactic diversity, makes for lousy typography and thus low readability.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Macros&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;A function that transforms the AST of its operands at &lt;em&gt;compile&lt;/em&gt; time to new code.&lt;/li&gt;
&lt;li&gt;Macros can be used to generate arbitrary new statements and control structures.

&lt;ul&gt;
&lt;li&gt;Domain specific languages, in particular, are very easy to implement in Lisp thanks to macros.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Macros can also be used to perform code optimizations at compile time&lt;sup id=&quot;fnref:12&quot;&gt;&lt;a href=&quot;#fn:12&quot; rel=&quot;footnote&quot;&gt;12&lt;/a&gt;&lt;/sup&gt; (similar to  &amp;ldquo;template metaprogramming&amp;rdquo; in C++).&lt;/li&gt;
&lt;li&gt;Fluent use of macros requires the host language to be homoiconic, which is rare. Thus Lisp remains the only well-known language family that has macros.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lisp Conditions and Restarts&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Allows bidirectional communication between different parts of the call stack. More powerful than exceptions, since conditions can not only unwind the stack but also wind it back again via a restart.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Call-with-current-continuation&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Allows you to save the current execution state of the program in a variable and jump back to it later. Multiple times, even. It&amp;rsquo;s like a friggin' time machine. You can implement fairly complex control flow operators with this function.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a id=&quot;other&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Other&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fexprs&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;A function whose operands are passed to it at runtime without being evaluated.&lt;/li&gt;
&lt;li&gt;Similar to macros and lazy evaluation in terms of power.&lt;/li&gt;
&lt;li&gt;Has fallen out of favor since the 1980s due to being difficult for compilers to optimize. Also it is hard to provide good error messages.&lt;/li&gt;
&lt;li&gt;Furthermore most fexpr functions tend to rely on &lt;em&gt;eval&lt;/em&gt; to continue evaluating its operands. The use of &lt;em&gt;eval&lt;/em&gt; has its own problems&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;!-- TODO: Add Prolog --&gt;


&lt;h3&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/20/visual-guide-to-programming-language-properties/&quot;&gt;Visual Guide to Programming Language Properties&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Shows programming language features, how they are related, and which features are present in popular languages.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Visualizes some of the features discussed in this article.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/03/01/notes-on-racket/&quot;&gt;Notes on Racket&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes Racket, a dialect of Lisp with batteries included.&lt;/em&gt;&lt;br/&gt;
&lt;em&gt;Useful for implementing other languages and creating cross-platform GUI programs.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/25/notes-on-prolog/&quot;&gt;Notes on Prolog&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Describes Prolog, a highly declarative language.&lt;/em&gt;&lt;br/&gt;
&lt;em&gt;Useful for exploring and verifying proofs.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/02/02/learnings-from-sicp/&quot;&gt;Learnings from SICP (and Lisp)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Discusses computer science concepts and how they manifest in various programming languages.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div style=&quot;padding: .8em 1em .8em; margin-bottom: 1em; border: 1px solid #94da3a;&quot;&gt;
    &lt;p style=&quot;font-weight: bold; color: #487858;&quot;&gt;
        Series
    &lt;/p&gt;
    &lt;p style=&quot;margin-bottom: 0em;&quot;&gt;
        This article is part of the &lt;a href=&quot;/articles/2013/05/11/book-outline/&quot;&gt;Programming for Perfectionists&lt;/a&gt; series.
    &lt;/p&gt;
&lt;/div&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;For example it is undefined what happens when you add to an integer variable and the variable overflows. In most compilers adding 1 to the largest integer wraps around to result in the smallest integer, and thus a number of programs depend on this behavior. Other compilers &lt;a href=&quot;http://thiemonagel.de/2010/01/signed-integer-overflow/&quot;&gt;assume overflow is impossible&lt;/a&gt;.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Steve Yegge has a great rant on the over-focus on objects in the Java community: &lt;a href=&quot;http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html&quot;&gt;Execution in the Kingdom of Nouns&lt;/a&gt;&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;C# is by design almost a direct copy of Java. It amazes me that Microsoft (C#&amp;rsquo;s sponsor) would spend so much effort making a copy of an existing language.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;If you invoke an uninitialized event-property, it will throw a &lt;code&gt;NullReferenceException&lt;/code&gt; instead of ignoring your request, as you would expect. Workaround by initializing events with an empty delegate.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;I am referring to the &lt;a href=&quot;http://www.refactoring.com/catalog/introduceForeignMethod.html&quot;&gt;Foreign Method&lt;/a&gt; design pattern here, not a native function from a &lt;a href=&quot;http://en.wikipedia.org/wiki/Foreign_function_interface&quot;&gt;foreign function interface&lt;/a&gt;.&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;Hence workarounds like &lt;a href=&quot;http://requirejs.org&quot;&gt;RequireJS&lt;/a&gt; to get includes and modules.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;Hence reimplementions of class semantics in libraries like MooTools, Prototype, and &lt;a href=&quot;http://ejohn.org/blog/simple-javascript-inheritance/&quot;&gt;random blog posts&lt;/a&gt;. (That blog post has the best implementation, IMHO.)&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;Hence recommendations to always use &lt;code&gt;===&lt;/code&gt; instead of &lt;code&gt;==&lt;/code&gt;.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:9&quot;&gt;
&lt;p&gt;Hence recommendations to only depend on the &amp;ldquo;truthy&amp;rdquo; and &amp;ldquo;falsy&amp;rdquo; values of expressions instead of direct comparisons with &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.&lt;a href=&quot;#fnref:9&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:10&quot;&gt;
&lt;p&gt;Want to implement Ruby&amp;rsquo;s &lt;code&gt;until&lt;/code&gt; loop or &lt;code&gt;unless&lt;/code&gt; conditional? No problem.&lt;a href=&quot;#fnref:10&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:11&quot;&gt;
&lt;p&gt;There are more dialects of Lisp than any other language I can think of. These 3 (Common Lisp, Scheme, and Clojure) are just the most popular dialects. I&amp;rsquo;ve directly used &lt;a href=&quot;/articles/2013/03/01/notes-on-racket/&quot;&gt;Racket&lt;/a&gt; in the past, which is itself a dialect of Scheme.&lt;a href=&quot;#fnref:11&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:12&quot;&gt;
&lt;p&gt;Prismatic performs efficient &lt;a href=&quot;http://blog.getprismatic.com/blog/2013/1/22/the-magic-of-macros-lighting-fast-templating-in-clojurescript&quot;&gt;compile-time DOM templating&lt;/a&gt; in ClojureScript using macros.&lt;a href=&quot;#fnref:12&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/01/15/things-i-wish-i-knew-before-working-in-industry</id>
   <title>Things I Wish I Knew Before Working in Industry</title>
   <published>2013-01-15T00:00:00+00:00</published>
   <updated>2021-02-23T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Business"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/01/15/things-i-wish-i-knew-before-working-in-industry/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;A representative from IBM came to visit me in college several years
ago&lt;!-- in April 2008 --&gt; when I was a student and talked about several things
he wished he knew before working in the software industry.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
I&amp;rsquo;ve found his advice to be very useful at various points during my career.
And would like to share it again with you now, in outline form:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: &lt;strong&gt;Bolded&lt;/strong&gt; points I&amp;rsquo;ve found to be especially useful.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Technology&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Future: integration&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Needed: ease-of-use &amp;amp; less complexity&lt;/li&gt;
&lt;li&gt;Do &lt;em&gt;not&lt;/em&gt; reinvent wheels!

&lt;ul&gt;
&lt;li&gt;you&amp;rsquo;ll never finish the project&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Technical Knowledge&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Learn to learn&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t need to take a class to learn something&lt;/li&gt;
&lt;li&gt;Learn a little about a lot of things&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Read news highlights from worthwhile sources&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Problem Solving&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build a network of people. Asking for advice is quicker than learning the hard way.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;There is always more than one way to do something.&lt;br/&gt;
Weigh the pros/cons of each – then pick and choose.&lt;/li&gt;
&lt;li&gt;Innovate &lt;em&gt;before&lt;/em&gt; you execute. Think critically before you act.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Business &amp;amp; Technology&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Technology adoption is driven by &lt;em&gt;business&lt;/em&gt;. (practicality)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Business is nothing without technology.&lt;br/&gt;
Technology is nothing without business.&lt;/li&gt;
&lt;li&gt;If you build a better mousetrap, they will not come.&lt;/li&gt;
&lt;li&gt;A project, no matter how advanced, is doomed for failure without a paying customer.&lt;/li&gt;
&lt;li&gt;Think about TCO (&lt;em&gt;total&lt;/em&gt; cost of ownership) and ROI (return on investment).&lt;br/&gt;
You must always justify your returns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Communication with &lt;em&gt;managers&lt;/em&gt; and &lt;em&gt;customers&lt;/em&gt; is vital!&lt;/strong&gt;&lt;br/&gt;
If you can&amp;rsquo;t get someone to adopt your solution, what&amp;rsquo;s the point?&lt;/li&gt;
&lt;li&gt;There is a difference between removing barriers and creating incentive (for a customer to switch to my project/product). You need both.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Promotions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s not &lt;em&gt;what&lt;/em&gt; you know.&lt;br/&gt;
It&amp;rsquo;s not &lt;em&gt;who&lt;/em&gt; you know.&lt;br/&gt;
&lt;strong&gt;It&amp;rsquo;s &lt;em&gt;who&lt;/em&gt; knows &lt;em&gt;what&lt;/em&gt; you know.&lt;/strong&gt;&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Doing more of the same is not enough.

&lt;ul&gt;
&lt;li&gt;Need to try new things – take on more responsibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Doing what is asked is not enough.&lt;/li&gt;
&lt;li&gt;Ask you manager what the expectations are.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Working with Others&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Credit + gratitude are not limited resources.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Say thank you!&lt;/li&gt;
&lt;li&gt;Give credit where due.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Be ambitious but be humble.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t make assumptions about others.

&lt;ul&gt;
&lt;li&gt;Give people the benefit of the doubt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Your lack of planning does not mean I need to treat your request as urgent.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Do what you say you will. Keep your word.

&lt;ul&gt;
&lt;li&gt;reliable&lt;/li&gt;
&lt;li&gt;dependable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The best humor is &lt;em&gt;self-deprecating&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;There is always someone faster, smarter, and better looking.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Managers&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;They don&amp;rsquo;t have a magic wand. They don&amp;rsquo;t automatically fix problems.&lt;/li&gt;
&lt;li&gt;Managers do not have a superset of the employees' (team members') knowledge.&lt;/li&gt;
&lt;li&gt;Managers can&amp;rsquo;t read minds. Don&amp;rsquo;t assume. Communicate explicitly.&lt;/li&gt;
&lt;li&gt;You are responsible for your own career. But ask for help.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;You and Your Job&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Your job is what you make of it. Don&amp;rsquo;t be confined by a job description.&lt;/li&gt;
&lt;li&gt;Work/Life balance doesn&amp;rsquo;t have good default settings. You must do &lt;em&gt;explicit&lt;/em&gt; actions.

&lt;ul&gt;
&lt;li&gt;plan&lt;/li&gt;
&lt;li&gt;schedule for success&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You are not your job. Do not define yourself like this.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Workers&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;We&amp;rsquo;re employed to &lt;em&gt;add value&lt;/em&gt;, not spend money.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s easy to stay busy, but are you accomplishing anything &lt;em&gt;worthwhile&lt;/em&gt;?

&lt;ul&gt;
&lt;li&gt;don&amp;rsquo;t needlessly clutter your schedule&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you aren&amp;rsquo;t looking at it from a &lt;em&gt;customer perspective&lt;/em&gt;, you aren&amp;rsquo;t looking at it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You can&amp;rsquo;t do everything. Pick what you &lt;em&gt;won&amp;rsquo;t&lt;/em&gt; do.&lt;/strong&gt; (The world won&amp;rsquo;t end.)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Employment&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t expect your first job to be your dream job. Look for a &lt;em&gt;path&lt;/em&gt;, not an &lt;em&gt;endpoint&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Be willing to stretch your comfort zone.

&lt;ul&gt;
&lt;li&gt;geographically, work type, etc.&lt;/li&gt;
&lt;li&gt;Otherwise you&amp;rsquo;ll stagnate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Know your employer&amp;rsquo;s business model.

&lt;ul&gt;
&lt;li&gt;Examples:

&lt;ul&gt;
&lt;li&gt;HP = selling ink;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.investopedia.com/how-microsoft-makes-money-4798809&quot;&gt;Microsoft&lt;/a&gt; = selling Office, Windows, and cloud services;&lt;/li&gt;
&lt;li&gt;Apple = &lt;s&gt;iPods&lt;/s&gt; iPhones and (to some extent) Macs&lt;/li&gt;
&lt;li&gt;Facebook, Google = selling ads&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Take a look at the annual reports for your company.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get &lt;em&gt;internships&lt;/em&gt;, even if with competitors, maybe even delaying graduation.&lt;/strong&gt;&lt;sup id=&quot;fnref:6&quot;&gt;&lt;a href=&quot;#fn:6&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;

&lt;ul&gt;
&lt;li&gt;It gives experience.&lt;/li&gt;
&lt;li&gt;Increases employment opportunities.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Start looking and prepare much earlier.&lt;sup id=&quot;fnref:7&quot;&gt;&lt;a href=&quot;#fn:7&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Successful Employment&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you want to make a difference, look for chaos.&lt;br/&gt;
Stable environments offer little opportunity.&lt;sup id=&quot;fnref:8&quot;&gt;&lt;a href=&quot;#fn:8&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Good employees &lt;em&gt;deal&lt;/em&gt; with challenges instead of pouting. &lt;em&gt;Adapt&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Stay above the commodity line (with regard to skill set and type of work done).&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Life&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Understand other people&amp;rsquo;s &lt;em&gt;motivations&lt;/em&gt;.

&lt;ul&gt;
&lt;li&gt;Makes it easier to find new ways of solving the underlying goal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Define your values and goals.

&lt;ul&gt;
&lt;li&gt;ex: What type of job do you want?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Your &lt;em&gt;behaviors&lt;/em&gt; should support your goals.&lt;/li&gt;
&lt;li&gt;Expect your goals to change. Success is dynamic.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t let &lt;em&gt;others&lt;/em&gt; define success for you.&lt;/li&gt;
&lt;li&gt;You can get rich by getting more or &lt;em&gt;wanting less&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Life is one great balancing act.

&lt;ul&gt;
&lt;li&gt;There&amp;rsquo;s no single right way of doing things.&lt;/li&gt;
&lt;li&gt;Balancing your priorities and goals is important.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;&lt;em&gt;Related Articles&lt;/em&gt;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/08/03/skills-i-learned-at-microsoft/&quot;&gt;Skills I Learned at Microsoft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/08/04/skills-i-am-learning-at-splunk/&quot;&gt;Skills I Learned at Splunk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: lightgray;&quot;&gt;Skills I&amp;rsquo;m Learning at TechSmart&lt;/span&gt; - A future article. 🙂&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/articles/2013/01/08/programming-is-fun-but-what-matters-is-solving-a-real-problem/&quot;&gt;Programming is Fun. But What Matters is Solving a Real Problem.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Sadly I have lost the name of the presenter from IBM who gave this talk originally.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;Apple has always been smart about creating integrated products and experiences. In 2020 Apple announced the M1, an ARM system-on-chip (SOC) with &lt;em&gt;incredible&lt;/em&gt; performance. &lt;a href=&quot;https://singhkays.com/blog/apple-silicon-m1-black-magic/&quot;&gt;The internet exploded.&lt;/a&gt;&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;I lean toward having a breadth of knowledge or being a generalist. But it&amp;rsquo;s also to have a deep specialization in one or two areas too. &lt;a href=&quot;https://alexkondov.com/the-t-shaped-engineer/&quot;&gt;The T-Shaped Engineer&lt;/a&gt; gives more insight into the tradeoffs of having generalist vs. specialist skills.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;For news of general interest to technologists I like &lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;Hacker News&lt;/a&gt;. There&amp;rsquo;s also frequently a &lt;a href=&quot;https://www.reddit.com/&quot;&gt;subreddit&lt;/a&gt; for most topics. For example I&amp;rsquo;ve been liking &lt;a href=&quot;https://www.reddit.com/r/django/&quot;&gt;r/django&lt;/a&gt; recently for Django-related information.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;It&amp;rsquo;s not enough to be doing awesome things regularly. If you want that activity to pay off in increasing your luck, you&amp;rsquo;ll also need to find ways to let folks know what you&amp;rsquo;re up to, especially those with similar values and mission-alignment. Doing both will increase your &lt;a href=&quot;https://www.codusoperandi.com/posts/increasing-your-luck-surface-area&quot;&gt;luck surface area&lt;/a&gt; and opportunities will come your way more often. Luck is where preparation meets opportunity, but you can actually increase opportunities!&lt;a href=&quot;#fnref:5&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:6&quot;&gt;
&lt;p&gt;While in college I interned at several smallish companies (plus Google) and I can attest that my experiences there, in environments of different sizes, helped me learn what kind of work environment I was most interested in aiming for.&lt;a href=&quot;#fnref:6&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:7&quot;&gt;
&lt;p&gt;One of the most valuable classes I took in college assigned me the task of creating an online portfolo website. Although the &lt;a href=&quot;/prism/projects/&quot;&gt;initial version&lt;/a&gt; of that (and this) site was a bit rough, later editions were quite helpful in landing positions. In particular it helped get the attention of my cofounder at &lt;a href=&quot;https://www.techsmart.codes/&quot;&gt;TechSmart&lt;/a&gt;. ✨&lt;a href=&quot;#fnref:7&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:8&quot;&gt;
&lt;p&gt;Google has the best actual onsite benefits of any company I&amp;rsquo;ve ever seen. (I worked there a while back in 2007.) But this cushiness means the engineers there don&amp;rsquo;t have the same incentives to be cutting edge. Multiple high-profile engineers, notably &lt;a href=&quot;https://medium.com/@steve.yegge/why-i-left-google-to-join-grab-86dfffc0be84&quot;&gt;Steve Yegge&lt;/a&gt; and &lt;a href=&quot;https://paygo.media/p/25171&quot;&gt;Waze&amp;rsquo;s CEO Noam Bardin&lt;/a&gt;, have written about why they eventually had to leave Google in order to make better headway in &lt;a href=&quot;/articles/2013/01/08/programming-is-fun-but-what-matters-is-solving-a-real-problem/&quot;&gt;making a difference in the world&lt;/a&gt;. All of that said, Google is still &lt;em&gt;very&lt;/em&gt; cushy and I don&amp;rsquo;t think any less of those who choose to work there.&lt;a href=&quot;#fnref:8&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2013/01/08/programming-is-fun-but-what-matters-is-solving-a-real-problem</id>
   <title>Programming is Fun. But What Matters is Solving a Real Problem.</title>
   <published>2013-01-08T00:00:00+00:00</published>
   <updated>2013-01-08T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Business"/>
   
     <category term="Personal"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2013/01/08/programming-is-fun-but-what-matters-is-solving-a-real-problem/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;I love programming. It tickles me when I stumble across a new programming language that lets me express concepts in a more clear and direct fashion. I love the cleanness and order that results after a good round of refactoring&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. I enjoy the challenge of hacking away at a fiddly problem and testing all the cases to get a correct and bulletproof solution.&lt;/p&gt;

&lt;p&gt;However I have realized programming is merely an activity. It is a &lt;em&gt;means&lt;/em&gt;, not an &lt;em&gt;end&lt;/em&gt;. My work is not inherently valuable because I have created a piece of software. Rather it is because I have created software &lt;em&gt;that solves somebody&amp;rsquo;s problem&lt;/em&gt;.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Therefore it is the &lt;em&gt;problem&lt;/em&gt; that deserves the most attention if you want to make a difference that people care about. In that vein I have been learning about the precepts of Customer Development and Customer Discovery, which deals with how to efficiently interact with customers to discover a problem that they care about.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Direct customer interaction, such as through in-person interviews of the general public, is way outside my comfort zone. However I will persevere. I think it is a very important skill for actually making a dent in the universe.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;&lt;em&gt;Refactoring&lt;/em&gt; is a systematic method for code cleanup: improving the structure of existing code without changing its behavior. I highly recommend the book &lt;a href=&quot;http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672&quot;&gt;Refactoring&lt;/a&gt; if you want a deep-dive into the topic.&lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;&lt;!-- Speculation: --&gt; Business majors &amp;amp; managers recognize early on the importance of solving business problems. After all, their training is around organizing other people to solve problems they identify. (Although I feel they often focus overly on managing and not enough on problem identification.)&lt;a href=&quot;#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;For a great practical workboard around Customer Discovery (which is the first quarter of Customer Development), I highly recommend Ash Maurya&amp;rsquo;s &lt;a href=&quot;http://www.amazon.com/Running-Lean-Iterate-Works-OReilly/dp/1449305172&quot;&gt;Running Lean&lt;/a&gt;. For a full overview of Customer Development, I recommend Steve Blank&amp;rsquo;s &lt;a href=&quot;http://www.amazon.com/Four-Steps-Epiphany-Successful-Strategies/dp/0976470705&quot;&gt;The Four Steps to the Epiphany&lt;/a&gt;.&lt;a href=&quot;#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;Steve Jobs famously said he wanted to &amp;ldquo;put a dent in the universe&amp;rdquo;. And boy did he ever.&lt;a href=&quot;#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2012/12/16/why-i-no-longer-use-drupal</id>
   <title>Why I no longer use Drupal</title>
   <published>2012-12-16T00:00:00+00:00</published>
   <updated>2012-12-16T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
     <category term="Productivity"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2012/12/16/why-i-no-longer-use-drupal/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;p&gt;&lt;em&gt;&lt;b&gt;TLDR:&lt;/b&gt; Drupal is overly complex for a personal blog. It is hard to maintain. Simple static site generators are easier to work with in the long term.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My portfolio website was written during college using hand-coded HTML and used server-side includes to bring in common navigation.&lt;/p&gt;

&lt;p&gt;Then in January 2010 I remade my site in Drupal. It gained lots of fancy features such as first-class support for project categories and project languages. You could subscribe to almost any page as a feed. There were project specific updates that could be commented on. From a feature point of view, it rocked.&lt;/p&gt;

&lt;p&gt;But some problems became apparent over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security updates were frequent and difficult to apply correctly.&lt;/li&gt;
&lt;li&gt;I didn&amp;rsquo;t like writing articles on the site because I couldn&amp;rsquo;t use simple markup formats such as Markdown.

&lt;ul&gt;
&lt;li&gt;Drupal has no good editor plugins for markup languages.&lt;/li&gt;
&lt;li&gt;And its visual HTML editor generates messy HTML.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The theme I used for the site was complex and hard to modify.

&lt;ul&gt;
&lt;li&gt;And the CSS often interfered with my article markup, necessitating me to drop into HTML when editing certain articles.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There was no sane way to test structural changes to the site locally and then automatically deploy them to production.

&lt;ul&gt;
&lt;li&gt;Normally this would be done by keeping the site structure in the filesystem and all user content in a database. This allows the filesystem contents to be easily deployed using &lt;code&gt;git push&lt;/code&gt;, &lt;code&gt;rsync&lt;/code&gt;, or similar techniques.&lt;/li&gt;
&lt;li&gt;Drupal, by contrast, keeps its site structure in both the filesystem &lt;em&gt;and&lt;/em&gt; in the database, along with user-generated content. Updating only the parts of the database related to site structure is cumbersome and error-prone.&lt;/li&gt;
&lt;li&gt;Thus, I couldn&amp;rsquo;t really change the site structure after my initial deployment to production.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Nothing was in revision control, which made me nervous.&lt;/li&gt;
&lt;li&gt;I had to hack the Drupal core to get my contact form to work with my web hosting provider.&lt;/li&gt;
&lt;li&gt;Most of the features of the site weren&amp;rsquo;t being used by readers.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So now I am rewriting my site yet again in straight HTML (via a simple static site generator) and outsourcing all user generated content (like comments) to third party service providers.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple simple simple.&lt;/li&gt;
&lt;li&gt;Automatic security. The web server just serves static files.&lt;/li&gt;
&lt;li&gt;Automatic scalability, for the same reason.&lt;/li&gt;
&lt;li&gt;Simple authoring in Markdown with powerful client-side text editors.&lt;/li&gt;
&lt;li&gt;Instant deployment with &lt;code&gt;git push&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Everything in revision control.&lt;/li&gt;
&lt;li&gt;I can use any web hosting provider. Hell, I can just use &lt;a href=&quot;http://pages.github.com&quot;&gt;GitHub Pages&lt;/a&gt; for free.&lt;/li&gt;
&lt;li&gt;Ultimate control over the site theme and CSS. I can fix problems myself.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 
 <entry>
   <id>https://dafoster.net/articles/2010/11/13/retrospect-vs-time-machine</id>
   <title>Retrospect vs. Time Machine</title>
   <published>2010-11-13T00:00:00+00:00</published>
   <updated>2012-12-21T00:00:00+00:00</updated>
   
     <category term="Software"/>
   
   <link rel="alternate" href="https://dafoster.net/articles/2010/11/13/retrospect-vs-time-machine/?utm_source=atom&amp;utm_medium=feed&amp;utm_campaign=feed"/>
   <content type="html">&lt;h2&gt;The old Retrospect 6.0&lt;/h2&gt;

&lt;p&gt;In the past I have used Retrospect 6.0 to backup my Macs, since it was one of
the few programs that reliably backed up everything correctly, with all the
metadata intact. But it is looking much less attractive these days&amp;hellip;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It no longer finds my laptop on the network reliably, due to some bug.
Especially when switching between wireless and wired networks.
Thus I often miss backups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is slow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It does not groom backups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It stores everything inside a single monolithic file,
which is at risk of corruption.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;The new Retrospect 8.0&lt;/h2&gt;

&lt;p&gt;The latest version of Retropect (8.0) is somewhat better but has some problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It does not seem to backup all attributes correctly.
For example, volume icons do not seem to be restored correctly.
Inaccurate backups are useless.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is more complicated to use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatic grooming, although supported, is so slow to be practically unusable.
It takes maybe 2x as long to do one grooming operation as an incremental backup.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Time Machine&lt;/h2&gt;

&lt;p&gt;Now there is Time Machine. Since my primary systems are 10.5+, I can use it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It &lt;em&gt;should&lt;/em&gt; support reliable backup of all filesystem attributes,
since it was made by Apple, who is in a position to know about them.
Also, Apple typically makes solid products.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It has quick, automatic, incremental backups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It also grooms automatically while it is backing up. Grooming behavior is
intelligent, keeping snapshots at sensible intervals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The single-file restore interface is precise, intuitive, and fast.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Only wrinkle is that Time Machine is not really designed to backup to network
drives, however there are &lt;a href=&quot;http://code.stephenmorley.org/articles/time-machine-on-a-network-drive/&quot;&gt;instructions for circumventing this&lt;/a&gt;.
(Of course there is Time Machine + Time Capsule for network backups, but a
Capsule is egregiously expensive.)&lt;/p&gt;

&lt;h3&gt;2012 Update&lt;/h3&gt;

&lt;p&gt;Time Machine misses a few filesystem attributes that Retrospect 6.0 nailed back
in the day, like volume icons.&lt;/p&gt;

&lt;p&gt;I think it may also strip HFS+ extended attributes, since applications appear
to be quarantined after they are restored from a Time Machine backup.&lt;/p&gt;

&lt;p&gt;One last nitpick is that TM has very poor handling for bad media and bad blocks.
In particular if your primary hard drive develops bad blocks, which is an early
sign of imminent failure, Time Machine will choke and refuse to backup the
entire volume. And this is exactly at the time you need it your files backed up
the most, when your hard drive is likely to fail.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>